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

# Router

Cedana API for the inference router

## POST /v1/inference/router/authorize

> Authenticate with the inbound Cedana inference key and issue an opaque\
> authorization that resolve consumes exactly once.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana API for the inference router","name":"Router"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"AuthorizeRequest":{"properties":{"estimated_prompt_tokens":{"format":"int64","type":"integer"},"logical_model":{"type":"string"},"request_id":{"type":"string"}},"required":["request_id","logical_model"],"type":"object"},"AuthorizeResponse":{"properties":{"authorization_id":{"format":"uuid","type":"string"},"expires_at":{"format":"date-time","type":"string"},"route_generation":{"format":"int64","type":"integer"}},"required":["authorization_id","route_generation","expires_at"],"type":"object"},"HttpError":{"description":"Standard JSON error body for all 4xx/5xx responses.\n\nHandlers return plain-text errors internally; [`normalize_error_response`]\nconverts anything the stack produces (handlers, extractors, the auth layer)\nto this shape, so generated SDK clients can rely on a single error schema.","properties":{"message":{"description":"Human-readable description of what went wrong","type":"string"}},"required":["message"],"type":"object"}}},"paths":{"/v1/inference/router/authorize":{"post":{"operationId":"authorize","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeResponse"}}},"description":"Authorization issued"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Key budget exhausted"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Model not allowed for this API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unknown logical model"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Rate limit exceeded"},"4XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Client error"},"5XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Server error"}},"summary":"Authenticate with the inbound Cedana inference key and issue an opaque\nauthorization that resolve consumes exactly once.","tags":["Router"]}}}}
```

## GET /v1/inference/router/config

> Full routing snapshot for Switchyard, service-token-only. Generation is the sum of\
> the route generations; \`If-None-Match: "\<generation>"\` gets a 304.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana API for the inference router","name":"Router"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"RouterConfig":{"properties":{"generation":{"format":"int64","type":"integer"},"routes":{"items":{"$ref":"#/components/schemas/RouterRouteConfig"},"type":"array"},"schema_version":{"format":"int32","type":"integer"}},"required":["schema_version","generation","routes"],"type":"object"},"RouterRouteConfig":{"properties":{"classifier_profile_id":{"type":["string","null"]},"classifier_prompt":{"type":["string","null"]},"classifier_response_schema":{"type":["string","null"]},"generation":{"format":"int64","type":"integer"},"logical_model":{"type":"string"},"mode":{"type":"string"},"queue_timeout_ms":{"format":"int64","type":"integer"},"targets":{"items":{"$ref":"#/components/schemas/RouterTargetConfig"},"type":"array"}},"required":["logical_model","mode","queue_timeout_ms","generation","targets"],"type":"object"},"RouterTargetConfig":{"properties":{"current_replicas":{"format":"int32","type":"integer"},"draining":{"type":"boolean"},"max_queue_depth":{"format":"int32","type":"integer"},"max_replicas":{"format":"int32","type":"integer"},"min_replicas":{"format":"int32","type":"integer"},"node_hourly_usd":{"format":"double","type":"number"},"priority":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"ready":{"type":"boolean"},"service_url":{"description":"Stable internal service URL; never contains an activation/generation.","type":"string"},"target_concurrency":{"format":"int32","type":"integer"},"tier":{"type":"string"},"upstream_model":{"type":"string"}},"required":["profile_id","tier","priority","service_url","upstream_model","ready","draining","min_replicas","max_replicas","current_replicas","target_concurrency","max_queue_depth","node_hourly_usd"],"type":"object"},"HttpError":{"description":"Standard JSON error body for all 4xx/5xx responses.\n\nHandlers return plain-text errors internally; [`normalize_error_response`]\nconverts anything the stack produces (handlers, extractors, the auth layer)\nto this shape, so generated SDK clients can rely on a single error schema.","properties":{"message":{"description":"Human-readable description of what went wrong","type":"string"}},"required":["message"],"type":"object"}}},"paths":{"/v1/inference/router/config":{"get":{"operationId":"router_config","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterConfig"}}},"description":"Routing snapshot"},"304":{"description":"Generation unchanged"},"4XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Client error"},"5XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Server error"}},"summary":"Full routing snapshot for Switchyard, service-token-only. Generation is the sum of\nthe route generations; `If-None-Match: \"<generation>\"` gets a 304.","tags":["Router"]}}}}
```

## POST /v1/inference/router/metrics

> Accept batched metric samples from Switchyard into ClickHouse,\
> service-token-only.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana API for the inference router","name":"Router"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"MetricsBatch":{"properties":{"samples":{"items":{"$ref":"#/components/schemas/MetricSample"},"type":"array"}},"required":["samples"],"type":"object"},"MetricSample":{"properties":{"metric_name":{"type":"string"},"profile_id":{"type":"string"},"route":{"type":"string"},"timestamp":{"format":"int64","type":"integer"},"value":{"format":"double","type":"number"}},"required":["route","profile_id","metric_name","value","timestamp"],"type":"object"},"HttpError":{"description":"Standard JSON error body for all 4xx/5xx responses.\n\nHandlers return plain-text errors internally; [`normalize_error_response`]\nconverts anything the stack produces (handlers, extractors, the auth layer)\nto this shape, so generated SDK clients can rely on a single error schema.","properties":{"message":{"description":"Human-readable description of what went wrong","type":"string"}},"required":["message"],"type":"object"}}},"paths":{"/v1/inference/router/metrics":{"post":{"operationId":"router_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsBatch"}}},"required":true},"responses":{"200":{"description":"Samples ingested"},"4XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Client error"},"5XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Server error"}},"summary":"Accept batched metric samples from Switchyard into ClickHouse,\nservice-token-only.","tags":["Router"]}}}}
```

## POST /v1/inference/router/resolve

> Assign exactly one target for an authorized request, service-token only. A row lock\
> consumes the authorization once.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana API for the inference router","name":"Router"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"ResolveRequest":{"properties":{"active_streams_by_profile":{"additionalProperties":{"format":"int64","type":"integer"},"propertyNames":{"type":"string"},"type":"object"},"authorization_id":{"format":"uuid","type":"string"},"logical_model":{"type":"string"},"preferred_profile_id":{"type":["string","null"]},"queued_requests":{"format":"int64","type":"integer"},"request_id":{"type":"string"}},"required":["authorization_id","request_id","logical_model"],"type":"object"},"ResolveResponse":{"properties":{"activation_path":{"type":"string"},"decision_source":{"type":"string"},"fallback_used":{"type":"boolean"},"profile_id":{"type":"string"},"route_generation":{"format":"int64","type":"integer"},"target_name":{"type":"string"},"upstream_model":{"type":"string"}},"required":["profile_id","target_name","upstream_model","route_generation","decision_source","fallback_used","activation_path"],"type":"object"},"PendingResponse":{"properties":{"pending_profile_id":{"type":"string"},"retry_after_ms":{"format":"int64","type":"integer"}},"required":["pending_profile_id","retry_after_ms"],"type":"object"},"HttpError":{"description":"Standard JSON error body for all 4xx/5xx responses.\n\nHandlers return plain-text errors internally; [`normalize_error_response`]\nconverts anything the stack produces (handlers, extractors, the auth layer)\nto this shape, so generated SDK clients can rely on a single error schema.","properties":{"message":{"description":"Human-readable description of what went wrong","type":"string"}},"required":["message"],"type":"object"}}},"paths":{"/v1/inference/router/resolve":{"post":{"operationId":"resolve","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveResponse"}}},"description":"Target assigned"},"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingResponse"}}},"description":"Activation pending"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Authorization already consumed"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Authorization expired"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Queue full or activation deadline exceeded"},"4XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Client error"},"5XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Server error"}},"summary":"Assign exactly one target for an authorized request, service-token only. A row lock\nconsumes the authorization once.","tags":["Router"]}}}}
```

## POST /v1/inference/router/telemetry

> Accept one completed-request record from Switchyard, service-token-only.\
> Idempotent by request\_id: replays of the same completed record are no-ops.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana API for the inference router","name":"Router"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"TelemetryRecord":{"properties":{"activation_path":{"type":["string","null"]},"classifier_latency_ms":{"format":"int64","type":["integer","null"]},"classifier_profile_id":{"type":["string","null"]},"completion_tokens":{"format":"int64","type":["integer","null"]},"decision_source":{"type":["string","null"]},"end_to_end_latency_ms":{"format":"int64","type":["integer","null"]},"fallback_used":{"type":["boolean","null"]},"logical_model":{"type":"string"},"mean_inter_token_ms":{"format":"double","type":["number","null"]},"p95_inter_token_ms":{"format":"double","type":["number","null"]},"profile_id":{"type":["string","null"]},"prompt_tokens":{"format":"int64","type":["integer","null"]},"queue_ms":{"format":"int64","type":["integer","null"]},"request_id":{"type":"string"},"route_generation":{"format":"int64","type":["integer","null"]},"status_code":{"format":"int32","type":["integer","null"]},"stream_duration_ms":{"format":"int64","type":["integer","null"]},"ttft_ms":{"format":"int64","type":["integer","null"]},"upstream_attempts":{"format":"int32","type":["integer","null"]}},"required":["request_id","logical_model"],"type":"object"},"HttpError":{"description":"Standard JSON error body for all 4xx/5xx responses.\n\nHandlers return plain-text errors internally; [`normalize_error_response`]\nconverts anything the stack produces (handlers, extractors, the auth layer)\nto this shape, so generated SDK clients can rely on a single error schema.","properties":{"message":{"description":"Human-readable description of what went wrong","type":"string"}},"required":["message"],"type":"object"}}},"paths":{"/v1/inference/router/telemetry":{"post":{"operationId":"router_telemetry","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TelemetryRecord"}}},"required":true},"responses":{"200":{"description":"Record ingested"},"4XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Client error"},"5XX":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Server error"}},"summary":"Accept one completed-request record from Switchyard, service-token-only.\nIdempotent by request_id: replays of the same completed record are no-ops.","tags":["Router"]}}}}
```
