Skip to main content

Explain a Route

Dry-run a routing decision through the live resolver: get the ordered candidate chain an operation would use, or a fail-closed explanation, without spending a model call.

POST /v1/ai/routes:explain answers "what would this operation route to right now" without spending a model call. The question runs through the same resolver that serves live traffic, so the answer is evidence rather than a forecast: the ordered candidate chain that would serve the operation, and every candidate the policy discarded, each with the constraint that discarded it. For a compliance review, the rejected list is often the more valuable half, because it shows the policy actively removing what it is supposed to remove.

The request names an operation_type and may pin a model or a class. Unpinned, the resolver uses the operation's effective class and walks its chain. Pinning a model asks "could we be routed to this model for this operation", which is the direct way to verify a denial: a denied model appears under rejected with reason model_denied no matter what else would have permitted it. fallback_scope in the response reports how far fallback may reach for this plan, for example class_chain when the class's whole chain is in play.

When the policy permits no route, the response is still a success (the endpoint returns 201 on every answered question) with routable: false, a reason code, and a plain-language message. This is deliberate: a policy that permits no route is a valid configuration whose consequence is that the live call fails closed. The dry run reports that consequence honestly instead of dressing it up as a client error.

POST/v1/ai/routes:explain

Body fields

operation_type*stringThe operation to route, for example extraction or classification.
modelstringOptional. Pin a specific logical model instead of letting the operation's class choose.
classstringOptional. Pin a specific model class instead of the operation's mapped one.

cURL: Explain the extraction route

curl -X POST "https://api.talonic.com/v1/ai/routes:explain" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_type": "extraction", "model": "claude-sonnet", "class": "standard"}'

Response: 201 Routable plan

{
  "operation_type": "extraction",
  "routable": true,
  "class": "standard",
  "fallback_scope": "class_chain",
  "candidates": [
    { "model": "claude-sonnet", "provider": "bedrock", "region": "eu", "custom_endpoint": false }
  ],
  "rejected": [
    { "model": "gpt-balanced", "provider": "openai", "region": "global", "reason": "provider_not_allowed" }
  ]
}

Response: 201 Fail-closed explanation

{
  "operation_type": "document_ocr",
  "routable": false,
  "reason": "no_compliant_route",
  "message": "No route satisfies this workspace policy for this operation, so the call fails closed rather than reaching a provider the policy does not permit.",
  "candidates": [],
  "rejected": [
    { "model": "mistral-ocr", "provider": "mistral", "region": "global", "reason": "provider_not_allowed" }
  ]
}
The explainer evaluates the policy that is live right now, which for routing purposes is the active one. Use it immediately after activating a change to confirm the change did what was intended, and periodically as standing evidence: the response is produced by the production resolver, so it cannot drift from what production does.

candidates is ordered: the first entry is what a live call would try first, and later entries are the fallback order under the reported fallback_scope. Every candidate carries only model, provider, region, and custom_endpoint; wire-level model identifiers, endpoint hosts, and credentials never appear. That projection is the same one every route on this surface applies, so nothing about the platform's infrastructure crosses the API boundary through a dry run either.