> 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/inference.md).

# Inference

Cedana inference control plane

## GET /v1/inference/activations

> List activations joined with profiles

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"ModelActivationView":{"properties":{"activation_started_at":{"format":"date-time","type":["string","null"]},"compatibility_key":{"type":"string"},"desired_state":{"type":"string"},"endpoint":{"type":["string","null"]},"estimated_cold_start_ms":{"format":"int64","type":"integer"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"logical_model":{"type":"string"},"observed_generation":{"format":"int64","type":"integer"},"phase":{"type":"string"},"profile_id":{"type":"string"},"profile_revision":{"type":"string"},"ready":{"type":"boolean"},"ready_at":{"format":"date-time","type":["string","null"]},"updated_at":{"format":"date-time","type":"string"}},"required":["profile_id","logical_model","exact_model","profile_revision","compatibility_key","hosting_mode","estimated_cold_start_ms","desired_state","phase","ready","observed_generation","updated_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/activations":{"get":{"operationId":"list_activations","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ModelActivationView"},"type":"array"}}},"description":"Activations joined with profiles"},"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":"List activations joined with profiles","tags":["inference"]}}}}
```

## POST /v1/inference/activations/report

> Report activation state from the controller

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"ActivationReport":{"properties":{"desired_state":{"type":"string"},"endpoint":{"type":["string","null"]},"observed_generation":{"format":"int64","type":"integer"},"phase":{"type":"string"},"profile_id":{"type":"string"},"ready":{"type":"boolean"}},"required":["profile_id","desired_state","phase","ready"],"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/activations/report":{"post":{"operationId":"report_activation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivationReport"}}},"required":true},"responses":{"204":{"description":"Activation recorded"},"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":"Report activation state from the controller","tags":["inference"]}}}}
```

## GET /v1/inference/analytics

> Startup, serving, and storage aggregate

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"InferenceAnalytics":{"properties":{"evidence":{"type":"string"},"experiment_id":{"format":"uuid","type":["string","null"]},"profile_id":{"type":["string","null"]},"sample_count":{"minimum":0,"type":"integer"},"serving":{"$ref":"#/components/schemas/ServingAnalytics"},"startup":{"$ref":"#/components/schemas/StartupAnalytics"},"storage":{"$ref":"#/components/schemas/StorageAnalytics"},"window_hours":{"format":"int64","type":"integer"}},"required":["window_hours","startup","storage","serving","evidence","sample_count"],"type":"object"},"ServingAnalytics":{"properties":{"average_ttft_ms":{"format":"double","type":["number","null"]},"completion_tokens":{"format":"int64","type":"integer"},"deadline_misses":{"format":"int64","type":"integer"},"fallbacks":{"format":"int64","type":"integer"},"prompt_tokens":{"format":"int64","type":"integer"},"requests":{"format":"int64","type":"integer"},"tokens_per_second":{"format":"double","type":["number","null"]}},"required":["requests","fallbacks","deadline_misses","prompt_tokens","completion_tokens"],"type":"object"},"StartupAnalytics":{"properties":{"cold":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LatencyDistribution"}]},"restore":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LatencyDistribution"}]},"saved_p50_ms":{"format":"int64","type":["integer","null"]},"speedup_p50":{"format":"double","type":["number","null"]},"warm":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/LatencyDistribution"}]}},"type":"object"},"LatencyDistribution":{"properties":{"count":{"minimum":0,"type":"integer"},"p50_ms":{"format":"int64","type":"integer"},"p95_ms":{"format":"int64","type":"integer"}},"required":["count","p50_ms","p95_ms"],"type":"object"},"StorageAnalytics":{"properties":{"dedup_ratio":{"format":"double","type":["number","null"]},"incremental_ratio":{"format":"double","type":["number","null"]},"logical_bytes":{"format":"int64","type":"integer"},"physical_bytes":{"format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":"integer"},"transferred_bytes":{"format":"int64","type":"integer"},"written_bytes":{"format":"int64","type":"integer"}},"required":["logical_bytes","physical_bytes","written_bytes","reused_bytes","transferred_bytes"],"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/analytics":{"get":{"operationId":"analytics","parameters":[{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"experiment_id","required":false,"schema":{"format":"uuid","type":["string","null"]}},{"in":"query","name":"hours","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InferenceAnalytics"}}},"description":"Startup/storage/serving aggregate"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Startup, serving, and storage aggregate","tags":["inference"]}}}}
```

## GET /v1/inference/artifacts

> List checkpoint artefacts

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts":{"get":{"operationId":"list_artifacts","parameters":[{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"status","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"mode","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"limit","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CheckpointArtifactView"},"type":"array"}}},"description":"Checkpoint artefacts"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"List checkpoint artefacts","tags":["inference"]}}}}
```

## POST /v1/inference/artifacts

> Register a checkpoint artefact

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"RegisterArtifact":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"logical_bytes":{"format":"int64","type":["integer","null"]},"metadata":{},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":["string","null"]},"storage_tier":{"type":["string","null"]},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","compatibility_key","checkpoint_mode","uri"],"type":"object"},"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts":{"post":{"operationId":"register_artifact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterArtifact"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointArtifactView"}}},"description":"Existing artefact (idempotent)"},"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointArtifactView"}}},"description":"Artefact registered"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Register a checkpoint artefact","tags":["inference"]}}}}
```

## GET /v1/inference/artifacts/{artifact\_id}

> Get a checkpoint artefact

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts/{artifact_id}":{"get":{"operationId":"get_artifact","parameters":[{"in":"path","name":"artifact_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointArtifactView"}}},"description":"Artefact detail"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Get a checkpoint artefact","tags":["inference"]}}}}
```

## DELETE /v1/inference/artifacts/{artifact\_id}

> Soft-delete an artefact (golden requires force)

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/artifacts/{artifact_id}":{"delete":{"operationId":"delete_artifact","parameters":[{"in":"query","name":"force","required":false,"schema":{"type":["boolean","null"]}},{"in":"path","name":"artifact_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"Artefact soft-deleted"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Golden artefact requires force"},"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":"Soft-delete an artefact (golden requires force)","tags":["inference"]}}}}
```

## PATCH /v1/inference/artifacts/{artifact\_id}

> Update artefact status / restore count

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"UpdateArtifact":{"properties":{"restore_count_increment":{"description":"Bumps the stored restore_count. Kept for compatibility; do not build on it. No\ncaller sends it, and observed_restores replaces it.","type":["boolean","null"]},"status":{"type":["string","null"]}},"type":"object"},"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts/{artifact_id}":{"patch":{"operationId":"update_artifact","parameters":[{"in":"path","name":"artifact_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateArtifact"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointArtifactView"}}},"description":"Artefact updated"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Update artefact status / restore count","tags":["inference"]}}}}
```

## GET /v1/inference/artifacts/{artifact\_id}/ancestry

> Get the artefact parent chain

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts/{artifact_id}/ancestry":{"get":{"operationId":"artifact_ancestry","parameters":[{"in":"path","name":"artifact_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CheckpointArtifactView"},"type":"array"}}},"description":"Parent chain oldest-first"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Get the artefact parent chain","tags":["inference"]}}}}
```

## POST /v1/inference/artifacts/{artifact\_id}/promote

> Promote an artefact to a hotter tier

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"PromoteArtifact":{"properties":{"deadline_ms":{"format":"int64","type":["integer","null"]},"tier":{"type":"string"}},"required":["tier"],"type":"object"},"CheckpointArtifactView":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"checksum":{"type":["string","null"]},"compatibility_key":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"last_restored_at":{"description":"When a worker last became ready from this artefact.","format":"date-time","type":["string","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"logical_model":{"type":"string"},"metadata":{},"observed_restore_attempts":{"description":"Worker pods started from this artefact, ready or not. The gap against\nobserved_restores is the interesting part.","format":"int64","type":["integer","null"]},"observed_restores":{"description":"Worker pods started from this artefact that went on to serve. Counted from the\npods that ran, so it answers how many times the checkpoint was actually used.","format":"int64","type":["integer","null"]},"parent_artifact_id":{"type":["string","null"]},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":"string"},"residency":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/ArtifactResidency","description":"Whether the bytes this artefact names are still there. Filled in after\nthe row is read (see `annotate_artifacts`); never selected from SQL."}]},"restore_count":{"description":"Unmaintained; do not display. Only restore_count_increment on the artifact PATCH\nwrites it, and no caller sends that. Use observed_restores.","format":"int64","type":"integer"},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"status":{"type":"string"},"storage_tier":{"type":"string"},"updated_at":{"format":"date-time","type":"string"},"uri":{"type":"string"},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["artifact_id","profile_id","logical_model","exact_model","hosting_mode","compatibility_key","checkpoint_mode","storage_tier","uri","source","status","restore_count","metadata","created_at","updated_at"],"type":"object"},"ArtifactResidency":{"description":"Whether an artefact can still be restored from, and why. status is only what the\ncontrol plane last recorded, which a reboot does not update.","properties":{"artifact_boot_id":{"description":"Boot id recorded when the checkpoint was taken.","type":["string","null"]},"boot_tied":{"description":"True when the storage tier ties the artefact to a single boot of a\nsingle node (`memory`, `local`). Durable tiers survive reboots.","type":"boolean"},"flags_verified":{"description":"Whether the engine flags still match what the next worker would start with. The\ncompatibility key does not cover them.","type":["boolean","null"]},"node_boot_id":{"description":"Boot id the node is reporting now, per the latest cluster sync.","type":["string","null"]},"node_last_sync":{"format":"date-time","type":["string","null"]},"node_name":{"type":["string","null"]},"node_status":{"type":["string","null"]},"reason":{"description":"One sentence an operator can act on, naming the evidence.","type":"string"},"state":{"description":"restorable when every check in the controller's rejectArtifact passes; otherwise\nthe value names the check that failed.","type":"string"}},"required":["state","reason","boot_tied"],"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/artifacts/{artifact_id}/promote":{"post":{"operationId":"promote_artifact","parameters":[{"in":"path","name":"artifact_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromoteArtifact"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointArtifactView"}}},"description":"Artefact promoted"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Promote an artefact to a hotter tier","tags":["inference"]}}}}
```

## GET /v1/inference/capacity-intents

> List the latest capacity intent per profile. One per profile, newest first by\
> update, whatever its status, so a caller can show what was last asked for.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CapacityIntent":{"properties":{"created_at":{"description":"When this intent row was first created. Not when the request it currently\ndescribes was made: the row is reused for a repeated ask. Use requested_at for that.","format":"date-time","type":"string"},"deadline":{"format":"date-time","type":["string","null"]},"desired_replicas":{"format":"int32","type":"integer"},"desired_state":{"type":"string"},"generation":{"format":"int64","type":"integer"},"id":{"format":"uuid","type":"string"},"profile_id":{"type":"string"},"requested_at":{"description":"When a caller last asked for this exact state and replica count, so it orders\nrequests as they were made rather than as the row happened to change.","format":"date-time","type":"string"},"status":{"type":"string"},"updated_at":{"description":"When this row last changed for any reason, including the expiry sweep. Not an\nordering key for what a caller asked for.","format":"date-time","type":"string"}},"required":["id","profile_id","desired_state","desired_replicas","status","generation","created_at","updated_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/capacity-intents":{"get":{"operationId":"list_capacity_intents","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CapacityIntent"},"type":"array"}}},"description":"Latest capacity intent per profile"},"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":"List the latest capacity intent per profile. One per profile, newest first by\nupdate, whatever its status, so a caller can show what was last asked for.","tags":["inference"]}}}}
```

## POST /v1/inference/chat/completions

> OpenAI-compatible chat with routing. Switchyard owns the external surface and\
> does its own selection, so this is a simpler duplicate kept for existing callers.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/chat/completions":{"post":{"operationId":"chat_completions","requestBody":{"content":{"application/json":{"schema":{}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"Chat completion (streaming or not)"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Invalid API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Model not allowed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unknown model alias"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Rate limit or budget"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"No profile can meet deadline"},"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":"OpenAI-compatible chat with routing. Switchyard owns the external surface and\ndoes its own selection, so this is a simpler duplicate kept for existing callers.","tags":["inference"]}}}}
```

## GET /v1/inference/correlation

> Per-experiment correlation view

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CorrelationView":{"properties":{"activations":{"items":{"$ref":"#/components/schemas/NameCount"},"type":"array"},"artifacts":{"items":{"$ref":"#/components/schemas/ArtifactRef"},"type":"array"},"experiment_id":{"format":"uuid","type":"string"},"intents":{"items":{"$ref":"#/components/schemas/NameCount"},"type":"array"},"name":{"type":"string"},"observations":{"items":{"$ref":"#/components/schemas/NameCount"},"type":"array"},"policy_decisions":{"items":{"$ref":"#/components/schemas/NameCount"},"type":"array"},"scenario":{"type":"string"},"status":{"type":"string"},"usage":{"$ref":"#/components/schemas/CorrelationUsage"}},"required":["experiment_id","name","scenario","status","usage","intents","activations","observations","artifacts","policy_decisions"],"type":"object"},"NameCount":{"properties":{"count":{"format":"int64","type":"integer"},"name":{"type":"string"}},"required":["name","count"],"type":"object"},"ArtifactRef":{"properties":{"artifact_id":{"type":"string"},"checkpoint_mode":{"type":"string"},"status":{"type":"string"}},"required":["artifact_id","checkpoint_mode","status"],"type":"object"},"CorrelationUsage":{"properties":{"cold_start_avoided_ms":{"format":"int64","type":"integer"},"fallbacks":{"format":"int64","type":"integer"},"requests":{"format":"int64","type":"integer"},"successful_requests":{"format":"int64","type":"integer"}},"required":["requests","fallbacks","successful_requests","cold_start_avoided_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/correlation":{"get":{"operationId":"correlation","parameters":[{"in":"query","name":"experiment_id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CorrelationView"}}},"description":"Experiment correlation"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Experiment not found"},"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":"Per-experiment correlation view","tags":["inference"]}}}}
```

## GET /v1/inference/costs/breakdown

> Per-profile cost breakdown

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CostBreakdownRow":{"properties":{"activation_count":{"format":"int64","type":"integer"},"active_duration_s":{"format":"double","type":"number"},"compute_usd":{"format":"double","type":"number"},"fallback_usd":{"format":"double","type":"number"},"idle_time_s":{"format":"double","type":"number"},"node_seconds":{"format":"double","type":"number"},"profile_id":{"type":"string"},"release_latency_ms":{"format":"double","type":["number","null"]},"storage_usd":{"format":"double","type":"number"},"tokens_served":{"format":"int64","type":"integer"},"transfer_usd":{"format":"double","type":"number"}},"required":["profile_id","node_seconds","active_duration_s","idle_time_s","activation_count","compute_usd","storage_usd","transfer_usd","fallback_usd","tokens_served"],"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/costs/breakdown":{"get":{"operationId":"cost_breakdown","parameters":[{"in":"query","name":"hours","required":false,"schema":{"format":"int64","type":"integer"}},{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"experiment_id","required":false,"schema":{"format":"uuid","type":["string","null"]}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CostBreakdownRow"},"type":"array"}}},"description":"Per-profile cost breakdown"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Per-profile cost breakdown","tags":["inference"]}}}}
```

## GET /v1/inference/costs/config

> List cost rates

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CostConfig":{"properties":{"node_hourly_usd":{"format":"double","type":"number"},"profile_id":{"type":"string"},"storage_gb_hour_usd":{"format":"double","type":"number"},"transfer_gb_usd":{"format":"double","type":"number"}},"required":["profile_id","node_hourly_usd","storage_gb_hour_usd","transfer_gb_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/costs/config":{"get":{"operationId":"list_cost_config","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CostConfig"},"type":"array"}}},"description":"Cost rates"},"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":"List cost rates","tags":["inference"]}}}}
```

## POST /v1/inference/costs/config

> Set cost rates for a profile

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CostConfigUpsert":{"properties":{"node_hourly_usd":{"format":"double","type":"number"},"profile_id":{"type":"string"},"storage_gb_hour_usd":{"format":"double","type":"number"},"transfer_gb_usd":{"format":"double","type":"number"}},"required":["profile_id"],"type":"object"},"CostConfig":{"properties":{"node_hourly_usd":{"format":"double","type":"number"},"profile_id":{"type":"string"},"storage_gb_hour_usd":{"format":"double","type":"number"},"transfer_gb_usd":{"format":"double","type":"number"}},"required":["profile_id","node_hourly_usd","storage_gb_hour_usd","transfer_gb_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/costs/config":{"post":{"operationId":"upsert_cost_config","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostConfigUpsert"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostConfig"}}},"description":"Cost rates saved"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile not found"},"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":"Set cost rates for a profile","tags":["inference"]}}}}
```

## GET /v1/inference/costs/report

> Baseline vs treatment savings report

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CostReport":{"properties":{"baseline":{"$ref":"#/components/schemas/CostLeg"},"hours":{"format":"int64","type":"integer"},"node_seconds_saved":{"format":"double","type":"number"},"savings_pct":{"format":"double","type":"number"},"savings_usd":{"format":"double","type":"number"},"treatment":{"$ref":"#/components/schemas/CostLeg"},"treatment_escalation_rate":{"format":"double","type":"number"},"treatment_idle_time_s":{"format":"double","type":"number"},"treatment_quality":{"$ref":"#/components/schemas/CostQuality"},"treatment_release_latency_ms":{"format":"double","type":["number","null"]},"variance":{"type":["string","null"]}},"required":["hours","baseline","treatment","treatment_idle_time_s","treatment_escalation_rate","treatment_quality","savings_usd","savings_pct","node_seconds_saved"],"type":"object"},"CostLeg":{"properties":{"cost_usd":{"format":"double","type":"number"},"heavy_activation_count":{"format":"int64","type":"integer"},"heavy_active_duration_s":{"format":"double","type":"number"},"node_seconds":{"format":"double","type":"number"}},"required":["cost_usd","node_seconds","heavy_activation_count","heavy_active_duration_s"],"type":"object"},"CostQuality":{"properties":{"avg_ttft_ms":{"format":"double","type":["number","null"]},"refusal_rate":{"format":"double","type":"number"}},"required":["refusal_rate"],"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/costs/report":{"get":{"operationId":"cost_report","parameters":[{"in":"query","name":"hours","required":false,"schema":{"format":"int64","type":"integer"}},{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"experiment_id","required":false,"schema":{"format":"uuid","type":["string","null"]}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostReport"}}},"description":"Baseline vs treatment report"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Baseline vs treatment savings report","tags":["inference"]}}}}
```

## GET /v1/inference/experiments

> List experiments

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"ExperimentSummary":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"observations":{"format":"int64","type":"integer"},"parameters":{},"profile_id":{"type":["string","null"]},"scenario":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string"}},"required":["id","name","scenario","status","parameters","started_at","observations"],"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/experiments":{"get":{"operationId":"list_experiments","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ExperimentSummary"},"type":"array"}}},"description":"Experiments with observation counts"},"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":"List experiments","tags":["inference"]}}}}
```

## POST /v1/inference/experiments

> Create a load-test experiment

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CreateExperiment":{"properties":{"name":{"type":"string"},"parameters":{},"profile_id":{"type":["string","null"]},"scenario":{"type":"string"}},"required":["name","scenario"],"type":"object"},"Experiment":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"parameters":{},"profile_id":{"type":["string","null"]},"scenario":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string"}},"required":["id","name","scenario","status","parameters","started_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/experiments":{"post":{"operationId":"create_experiment","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExperiment"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}},"description":"Experiment created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Create a load-test experiment","tags":["inference"]}}}}
```

## GET /v1/inference/experiments/{id}

> Get an experiment's desired lifecycle state. Controllers use this after an\
> outbox wake-up rather than trusting a replayed event payload.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"Experiment":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"parameters":{},"profile_id":{"type":["string","null"]},"scenario":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string"}},"required":["id","name","scenario","status","parameters","started_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/experiments/{id}":{"get":{"operationId":"get_experiment","parameters":[{"description":"Experiment ID","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}},"description":"Experiment"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Experiment not found"},"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":"Get an experiment's desired lifecycle state. Controllers use this after an\noutbox wake-up rather than trusting a replayed event payload.","tags":["inference"]}}}}
```

## POST /v1/inference/experiments/{id}/complete

> Complete/cancel a running experiment

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CompleteExperiment":{"properties":{"status":{"type":"string"}},"required":["status"],"type":"object"},"Experiment":{"properties":{"completed_at":{"format":"date-time","type":["string","null"]},"id":{"format":"uuid","type":"string"},"name":{"type":"string"},"parameters":{},"profile_id":{"type":["string","null"]},"scenario":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"status":{"type":"string"}},"required":["id","name","scenario","status","parameters","started_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/experiments/{id}/complete":{"post":{"operationId":"complete_experiment","parameters":[{"in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteExperiment"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}},"description":"Experiment updated"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Running experiment not found"},"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":"Complete/cancel a running experiment","tags":["inference"]}}}}
```

## GET /v1/inference/fleets

> List fleets

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"Fleet":{"properties":{"availability":{"type":["string","null"]},"budgets":{},"created_at":{"format":"date-time","type":"string"},"fleet_id":{"type":"string"},"logical_model":{"type":"string"},"name":{"type":"string"},"profile_ids":{},"residency":{"type":["string","null"]}},"required":["fleet_id","name","logical_model","profile_ids","budgets","created_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/fleets":{"get":{"operationId":"list_fleets","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Fleet"},"type":"array"}}},"description":"Fleets"},"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":"List fleets","tags":["inference"]}}}}
```

## POST /v1/inference/fleets

> Create or update a fleet

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"FleetUpsert":{"properties":{"availability":{"type":["string","null"]},"budgets":{},"fleet_id":{"type":["string","null"]},"logical_model":{"type":"string"},"name":{"type":"string"},"profile_ids":{"items":{"type":"string"},"type":"array"},"residency":{"type":["string","null"]}},"required":["name","logical_model","profile_ids"],"type":"object"},"Fleet":{"properties":{"availability":{"type":["string","null"]},"budgets":{},"created_at":{"format":"date-time","type":"string"},"fleet_id":{"type":"string"},"logical_model":{"type":"string"},"name":{"type":"string"},"profile_ids":{},"residency":{"type":["string","null"]}},"required":["fleet_id","name","logical_model","profile_ids","budgets","created_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/fleets":{"post":{"operationId":"create_fleet","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FleetUpsert"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fleet"}}},"description":"Fleet saved"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Create or update a fleet","tags":["inference"]}}}}
```

## GET /v1/inference/fleets/{fleet\_id}

> Get a fleet

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"Fleet":{"properties":{"availability":{"type":["string","null"]},"budgets":{},"created_at":{"format":"date-time","type":"string"},"fleet_id":{"type":"string"},"logical_model":{"type":"string"},"name":{"type":"string"},"profile_ids":{},"residency":{"type":["string","null"]}},"required":["fleet_id","name","logical_model","profile_ids","budgets","created_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/fleets/{fleet_id}":{"get":{"operationId":"get_fleet","parameters":[{"in":"path","name":"fleet_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fleet"}}},"description":"Fleet detail"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Get a fleet","tags":["inference"]}}}}
```

## DELETE /v1/inference/fleets/{fleet\_id}

> Delete a fleet

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/fleets/{fleet_id}":{"delete":{"operationId":"delete_fleet","parameters":[{"in":"path","name":"fleet_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Fleet deleted"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile still routed"},"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":"Delete a fleet","tags":["inference"]}}}}
```

## GET /v1/inference/keys

> List issued inference keys

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"InferenceKeyView":{"properties":{"budget_usd":{"format":"double","type":["number","null"]},"created_at":{"format":"date-time","type":"string"},"key_id":{"type":"string"},"models":{},"name":{"type":"string"},"rate_limit_rps":{"format":"int64","type":["integer","null"]},"revoked_at":{"format":"date-time","type":["string","null"]},"tenant_id":{"type":["string","null"]}},"required":["key_id","name","models","created_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/keys":{"get":{"operationId":"list_inference_keys","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/InferenceKeyView"},"type":"array"}}},"description":"Issued keys"},"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":"List issued inference keys","tags":["inference"]}}}}
```

## POST /v1/inference/keys

> Issue a scoped inference API key

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CreateInferenceKey":{"properties":{"budget_usd":{"format":"double","type":["number","null"]},"models":{"items":{"type":"string"},"type":"array"},"name":{"type":"string"},"rate_limit_rps":{"format":"int64","type":["integer","null"]},"tenant_id":{"type":["string","null"]}},"required":["name"],"type":"object"},"CreatedInferenceKey":{"allOf":[{"$ref":"#/components/schemas/InferenceKeyView"},{"properties":{"raw_key":{"description":"The raw key, shown exactly once at creation.","type":"string"}},"required":["raw_key"],"type":"object"}]},"InferenceKeyView":{"properties":{"budget_usd":{"format":"double","type":["number","null"]},"created_at":{"format":"date-time","type":"string"},"key_id":{"type":"string"},"models":{},"name":{"type":"string"},"rate_limit_rps":{"format":"int64","type":["integer","null"]},"revoked_at":{"format":"date-time","type":["string","null"]},"tenant_id":{"type":["string","null"]}},"required":["key_id","name","models","created_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/keys":{"post":{"operationId":"create_inference_key","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInferenceKey"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedInferenceKey"}}},"description":"Key issued (raw shown once)"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Issue a scoped inference API key","tags":["inference"]}}}}
```

## DELETE /v1/inference/keys/{key\_id}

> Revoke an inference API key

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/keys/{key_id}":{"delete":{"operationId":"delete_inference_key","parameters":[{"in":"path","name":"key_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Key revoked"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Revoke an inference API key","tags":["inference"]}}}}
```

## GET /v1/inference/lifecycle-events

> The cluster's recent lifecycle events across all profiles, time-ascending, so a\
> UI can replay how the routing topology changed over time.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"LifecycleEventView":{"description":"One durably-persisted lifecycle event, across every profile in the cluster.","properties":{"event_id":{"format":"uuid","type":"string"},"generation":{"format":"int64","type":["integer","null"]},"kind":{"description":"Lifecycle kind, e.g. model.ready, route.published, route.withdrawn.","type":"string"},"occurred_at":{"format":"date-time","type":"string"},"payload":{},"profile_id":{"description":"The profile the event belongs to, when known. Null for cluster-wide events\nand for rows written before the column existed.","type":["string","null"]},"sequence":{"format":"int64","type":["integer","null"]}},"required":["event_id","kind","occurred_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/lifecycle-events":{"get":{"operationId":"list_lifecycle_events","parameters":[{"in":"query","name":"limit","required":false,"schema":{"format":"int64","type":"integer"}},{"description":"Only events at or after this instant, so a poller can page forward.","in":"query","name":"since","required":false,"schema":{"format":"date-time","type":["string","null"]}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/LifecycleEventView"},"type":"array"}}},"description":"Lifecycle events across all profiles"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"The cluster's recent lifecycle events across all profiles, time-ascending, so a\nUI can replay how the routing topology changed over time.","tags":["inference"]}}}}
```

Ingest one trusted lifecycle envelope over HTTP. Same event\_id dedupe and\
transactional ingestion as the RabbitMQ path.
---------------------------------------------

> Documented at /inference/lifecycle-events (same collection as the GET) so\
> generated SDKs get a single builder with both methods; the legacy\
> /inference/lifecycle/events path collides with it under kiota's name\
> sanitization, dropping the POST from the SDK. The legacy path stays\
> registered as an undocumented alias in api.rs for older clients.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"LifecycleEnvelope":{"description":"Shared envelope for trusted lifecycle events.","properties":{"action_id":{"description":"Checkpoint/restore action UUID when the event belongs to one.","format":"uuid","type":["string","null"]},"activation_id":{"description":"Model activation row UUID when applicable.","format":"uuid","type":["string","null"]},"artifact_id":{"description":"Checkpoint artifact UUID for checkpoint events.","format":"uuid","type":["string","null"]},"boot_id":{"type":["string","null"]},"cluster_id":{"description":"Nebius cluster (`clusters.id` UUID).","format":"uuid","type":"string"},"event_id":{"description":"Idempotency key: generated once per logical event and reused across\ntransport retries (RabbitMQ redelivery, HTTP retry).","format":"uuid","type":"string"},"generation":{"description":"Activation observed generation.","format":"int64","type":"integer"},"kind":{"description":"One of SUPPORTED_LIFECYCLE_KINDS.","type":"string"},"node_uid":{"description":"Node the event came from (checkpoint tmpfs artifacts are boot-tied).","format":"uuid","type":["string","null"]},"occurred_at":{"description":"When the event happened at the source (RFC3339 UTC).","format":"date-time","type":"string"},"payload":{"description":"Free-form JSON; required fields vary per kind."},"profile_id":{"description":"Deployment profile id (e.g. `qwen3-30b-a3b-l40s-fp8`).","type":"string"},"schema_version":{"description":"MUST be 1; anything else is dead-lettered on ingestion.","format":"int32","type":"integer"},"sequence":{"description":"Per-(cluster_id, activation_id) monotonic counter; 0 when not applicable.","format":"int64","type":"integer"},"workload_uid":{"description":"k8s pod/DGD UID when relevant.","type":["string","null"]}},"required":["schema_version","event_id","occurred_at","cluster_id","profile_id","kind"],"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/lifecycle-events":{"post":{"description":"Documented at /inference/lifecycle-events (same collection as the GET) so\ngenerated SDKs get a single builder with both methods; the legacy\n/inference/lifecycle/events path collides with it under kiota's name\nsanitization, dropping the POST from the SDK. The legacy path stays\nregistered as an undocumented alias in api.rs for older clients.","operationId":"ingest_lifecycle_event","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LifecycleEnvelope"}}},"required":true},"responses":{"204":{"description":"Lifecycle event accepted"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Invalid envelope (schema version or kind)"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unauthorized"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Duplicate event_id"},"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":"Ingest one trusted lifecycle envelope over HTTP. Same event_id dedupe and\ntransactional ingestion as the RabbitMQ path.","tags":["inference"]}}}}
```

## GET /v1/inference/metrics

> Routing metrics summary

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"MetricsSummary":{"properties":{"average_backend_latency_ms":{"format":"double","type":"number"},"average_routing_latency_ms":{"format":"double","type":"number"},"estimated_cold_start_avoided_ms":{"format":"int64","type":"integer"},"fallbacks":{"format":"int64","type":"integer"},"requests":{"format":"int64","type":"integer"},"successful_requests":{"format":"int64","type":"integer"}},"required":["requests","fallbacks","successful_requests","estimated_cold_start_avoided_ms","average_routing_latency_ms","average_backend_latency_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/metrics":{"get":{"operationId":"metrics","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricsSummary"}}},"description":"Routing metrics summary"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Invalid API key"},"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":"Routing metrics summary","tags":["inference"]}}}}
```

## GET /v1/inference/models

> OpenAI-compatible model aliases

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/models":{"get":{"operationId":"models","responses":{"200":{"content":{"application/json":{"schema":{}}},"description":"OpenAI models list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Invalid API key"},"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":"OpenAI-compatible model aliases","tags":["inference"]}}}}
```

## GET /v1/inference/observations

> List recent observations

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"ObservationView":{"properties":{"completion_tokens":{"format":"int64","type":["integer","null"]},"deadline_missed":{"type":["boolean","null"]},"duration_ms":{"format":"int64","type":["integer","null"]},"event_type":{"type":"string"},"evidence":{"type":"string"},"experiment_id":{"format":"uuid","type":["string","null"]},"fallback_used":{"type":["boolean","null"]},"id":{"format":"uuid","type":"string"},"logical_bytes":{"format":"int64","type":["integer","null"]},"observation_key":{"type":"string"},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":["string","null"]},"prompt_tokens":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"success":{"type":["boolean","null"]},"ttft_ms":{"format":"int64","type":["integer","null"]}},"required":["id","observation_key","event_type","evidence","source","started_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/observations":{"get":{"operationId":"list_observations","parameters":[{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"experiment_id","required":false,"schema":{"format":"uuid","type":["string","null"]}},{"in":"query","name":"event_type","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"limit","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ObservationView"},"type":"array"}}},"description":"Recent observations"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"List recent observations","tags":["inference"]}}}}
```

## POST /v1/inference/observations

> Record an observation

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"CreateObservation":{"properties":{"action_id":{"type":["string","null"]},"checkpoint_id":{"type":["string","null"]},"checkpoint_mode":{"type":["string","null"]},"cluster_id":{"type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"completion_tokens":{"format":"int64","type":["integer","null"]},"deadline_missed":{"type":["boolean","null"]},"deployment_id":{"type":["string","null"]},"dimensions":{},"duration_ms":{"format":"int64","type":["integer","null"]},"event_type":{"type":"string"},"evidence":{"type":"string"},"experiment_id":{"format":"uuid","type":["string","null"]},"fallback_used":{"type":["boolean","null"]},"logical_bytes":{"format":"int64","type":["integer","null"]},"metrics":{},"node_id":{"type":["string","null"]},"observation_key":{"type":"string"},"physical_bytes":{"format":"int64","type":["integer","null"]},"profile_id":{"type":["string","null"]},"prompt_tokens":{"format":"int64","type":["integer","null"]},"request_id":{"type":["string","null"]},"reused_bytes":{"format":"int64","type":["integer","null"]},"source":{"type":"string"},"started_at":{"format":"date-time","type":"string"},"storage_tier":{"type":["string","null"]},"success":{"type":["boolean","null"]},"transferred_bytes":{"format":"int64","type":["integer","null"]},"ttft_ms":{"format":"int64","type":["integer","null"]},"written_bytes":{"format":"int64","type":["integer","null"]}},"required":["observation_key","event_type","evidence","source","started_at"],"type":"object"},"Observation":{"properties":{"duration_ms":{"format":"int64","type":["integer","null"]},"event_type":{"type":"string"},"evidence":{"type":"string"},"experiment_id":{"format":"uuid","type":["string","null"]},"id":{"format":"uuid","type":"string"},"observation_key":{"type":"string"},"profile_id":{"type":["string","null"]},"source":{"type":"string"},"started_at":{"format":"date-time","type":"string"}},"required":["id","observation_key","event_type","evidence","source","started_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/observations":{"post":{"operationId":"create_observation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateObservation"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Observation"}}},"description":"Observation recorded"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Record an observation","tags":["inference"]}}}}
```

## GET /v1/inference/outbox

> Read durable outbox events

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"OutboxEvent":{"properties":{"aggregate_id":{"type":"string"},"aggregate_type":{"type":"string"},"created_at":{"format":"date-time","type":"string"},"event_type":{"type":"string"},"id":{"format":"int64","type":"integer"},"payload":{}},"required":["id","aggregate_type","aggregate_id","event_type","payload","created_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/outbox":{"get":{"operationId":"outbox","parameters":[{"in":"query","name":"consumer_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"after","required":false,"schema":{"format":"int64","type":["integer","null"]}},{"in":"query","name":"limit","required":false,"schema":{"format":"int64","type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/OutboxEvent"},"type":"array"}}},"description":"Outbox events after cursor"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Read durable outbox events","tags":["inference"]}}}}
```

## POST /v1/inference/outbox/ack

> Advance an outbox consumer cursor

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"AckOutbox":{"properties":{"consumer_id":{"type":"string"},"event_id":{"format":"int64","type":"integer"}},"required":["consumer_id","event_id"],"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/outbox/ack":{"post":{"operationId":"ack_outbox","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AckOutbox"}}},"required":true},"responses":{"204":{"description":"Cursor advanced"},"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":"Advance an outbox consumer cursor","tags":["inference"]}}}}
```

## GET /v1/inference/profiles

> List deployment profiles

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"DeploymentProfile":{"properties":{"backend_url":{"type":"string"},"compatibility_key":{"type":"string"},"dynamo_template":{},"estimated_cold_start_ms":{"format":"int64","type":"integer"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"logical_model":{"type":"string"},"max_queue_depth":{"format":"int32","type":"integer"},"max_replicas":{"format":"int32","type":"integer"},"min_replicas":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"profile_revision":{"type":"string"},"scale_down_idle_seconds":{"format":"int64","type":"integer"},"spec":{},"target_concurrency":{"format":"int32","type":"integer"}},"required":["profile_id","logical_model","exact_model","profile_revision","compatibility_key","backend_url","estimated_cold_start_ms","hosting_mode","spec","min_replicas","max_replicas","target_concurrency","max_queue_depth","scale_down_idle_seconds"],"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/profiles":{"get":{"operationId":"list_profiles","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/DeploymentProfile"},"type":"array"}}},"description":"List of deployment profiles"},"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":"List deployment profiles","tags":["inference"]}}}}
```

## POST /v1/inference/profiles

> Create an immutable deployment profile

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CreateProfile":{"properties":{"backend_url":{"type":"string"},"compatibility":{},"dynamo_template":{},"estimated_cold_start_ms":{"format":"int64","type":"integer"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"logical_model":{"type":"string"},"max_queue_depth":{"format":"int32","type":"integer"},"max_replicas":{"format":"int32","type":"integer"},"min_replicas":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"scale_down_idle_seconds":{"format":"int64","type":"integer"},"spec":{},"target_concurrency":{"format":"int32","type":"integer"}},"required":["profile_id","logical_model","exact_model","backend_url","spec"],"type":"object"},"DeploymentProfile":{"properties":{"backend_url":{"type":"string"},"compatibility_key":{"type":"string"},"dynamo_template":{},"estimated_cold_start_ms":{"format":"int64","type":"integer"},"exact_model":{"type":"string"},"hosting_mode":{"type":"string"},"logical_model":{"type":"string"},"max_queue_depth":{"format":"int32","type":"integer"},"max_replicas":{"format":"int32","type":"integer"},"min_replicas":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"profile_revision":{"type":"string"},"scale_down_idle_seconds":{"format":"int64","type":"integer"},"spec":{},"target_concurrency":{"format":"int32","type":"integer"}},"required":["profile_id","logical_model","exact_model","profile_revision","compatibility_key","backend_url","estimated_cold_start_ms","hosting_mode","spec","min_replicas","max_replicas","target_concurrency","max_queue_depth","scale_down_idle_seconds"],"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/profiles":{"post":{"operationId":"create_profile","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProfile"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentProfile"}}},"description":"Profile created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Checkpoint ownership conflict"},"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":"Create an immutable deployment profile","tags":["inference"]}}}}
```

## GET /v1/inference/profiles/{profile\_id}/checkpoint

> The latest checkpoint request for a profile, outstanding or finished

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CheckpointRequestView":{"description":"An on-demand checkpoint request and how far it has got.","properties":{"artifact_id":{"description":"The artifact the checkpoint produced, once it succeeded.","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"error":{"description":"Why it failed, in the controller's words.","type":["string","null"]},"kind":{"description":"checkpoint or restart. One row per profile, so asking twice returns the open one.","type":"string"},"profile_id":{"type":"string"},"reason":{"type":["string","null"]},"replace_existing":{"type":"boolean"},"request_id":{"description":"Identifies this attempt. A caller polling with the id it was given\ncannot be shown a later request's outcome as though it were its own.","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"started_at":{"format":"date-time","type":["string","null"]},"status":{"description":"pending → running → succeeded | failed","type":"string"}},"required":["profile_id","kind","request_id","status","replace_existing","requested_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/profiles/{profile_id}/checkpoint":{"get":{"operationId":"get_profile_checkpoint_request","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointRequestView"}}},"description":"Latest checkpoint request"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"No checkpoint has been requested"},"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":"The latest checkpoint request for a profile, outstanding or finished","tags":["inference"]}}}}
```

## POST /v1/inference/profiles/{profile\_id}/checkpoint

> Ask for a checkpoint of this profile's worker now. Covers the two cases the\
> automatic path refuses: a restored worker, and replacing an existing checkpoint.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"RequestCheckpoint":{"description":"What a caller asks for when it wants a checkpoint taken now.","properties":{"reason":{"description":"What this checkpoint is for, carried onto the artifact so a tier holding\nseveral has something to tell them apart by.","type":["string","null"]},"replace_existing":{"description":"Whether the previous checkpoint may be deleted to make room. On by default,\nbecause the tier holds barely more than one dump.","type":"boolean"}},"type":"object"},"CheckpointRequestView":{"description":"An on-demand checkpoint request and how far it has got.","properties":{"artifact_id":{"description":"The artifact the checkpoint produced, once it succeeded.","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"error":{"description":"Why it failed, in the controller's words.","type":["string","null"]},"kind":{"description":"checkpoint or restart. One row per profile, so asking twice returns the open one.","type":"string"},"profile_id":{"type":"string"},"reason":{"type":["string","null"]},"replace_existing":{"type":"boolean"},"request_id":{"description":"Identifies this attempt. A caller polling with the id it was given\ncannot be shown a later request's outcome as though it were its own.","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"started_at":{"format":"date-time","type":["string","null"]},"status":{"description":"pending → running → succeeded | failed","type":"string"}},"required":["profile_id","kind","request_id","status","replace_existing","requested_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/profiles/{profile_id}/checkpoint":{"post":{"operationId":"request_profile_checkpoint","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestCheckpoint"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointRequestView"}}},"description":"Checkpoint requested"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile not found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile does not checkpoint"},"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":"Ask for a checkpoint of this profile's worker now. Covers the two cases the\nautomatic path refuses: a restored worker, and replacing an existing checkpoint.","tags":["inference"]}}}}
```

## PATCH /v1/inference/profiles/{profile\_id}/checkpoint

> Report progress on a checkpoint request (controller only)

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"UpdateCheckpointRequest":{"description":"What the controller reports back about a request it picked up.","properties":{"artifact_id":{"type":["string","null"]},"error":{"type":["string","null"]},"request_id":{"description":"Correlates this report to the request it describes, so a late report from a\nsuperseded attempt cannot overwrite the current outcome.","format":"uuid","type":"string"},"status":{"description":"running when the dump starts, then succeeded or failed.","type":"string"}},"required":["request_id","status"],"type":"object"},"CheckpointRequestView":{"description":"An on-demand checkpoint request and how far it has got.","properties":{"artifact_id":{"description":"The artifact the checkpoint produced, once it succeeded.","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"error":{"description":"Why it failed, in the controller's words.","type":["string","null"]},"kind":{"description":"checkpoint or restart. One row per profile, so asking twice returns the open one.","type":"string"},"profile_id":{"type":"string"},"reason":{"type":["string","null"]},"replace_existing":{"type":"boolean"},"request_id":{"description":"Identifies this attempt. A caller polling with the id it was given\ncannot be shown a later request's outcome as though it were its own.","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"started_at":{"format":"date-time","type":["string","null"]},"status":{"description":"pending → running → succeeded | failed","type":"string"}},"required":["profile_id","kind","request_id","status","replace_existing","requested_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/profiles/{profile_id}/checkpoint":{"patch":{"operationId":"update_profile_checkpoint_request","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCheckpointRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointRequestView"}}},"description":"Updated"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unknown status"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"No checkpoint has been requested"},"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":"Report progress on a checkpoint request (controller only)","tags":["inference"]}}}}
```

## GET /v1/inference/profiles/{profile\_id}/hosting

> Hosting plan for a profile

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"ProfileHostingPlan":{"properties":{"checkpoint_owner":{"type":"string"},"checkpoint_request":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/CheckpointRequestView","description":"An outstanding on-demand checkpoint, or null. Carried on the hosting plan the\ncontroller already reads each pass, so it needs no extra poll."}]},"compatibility_key":{"type":"string"},"cpu_fixture":{"type":"boolean"},"dynamo_template":{},"hosting_mode":{"type":"string"},"profile_id":{"type":"string"},"profile_revision":{"type":"string"}},"required":["profile_id","hosting_mode","profile_revision","compatibility_key","checkpoint_owner","cpu_fixture"],"type":"object"},"CheckpointRequestView":{"description":"An on-demand checkpoint request and how far it has got.","properties":{"artifact_id":{"description":"The artifact the checkpoint produced, once it succeeded.","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"error":{"description":"Why it failed, in the controller's words.","type":["string","null"]},"kind":{"description":"checkpoint or restart. One row per profile, so asking twice returns the open one.","type":"string"},"profile_id":{"type":"string"},"reason":{"type":["string","null"]},"replace_existing":{"type":"boolean"},"request_id":{"description":"Identifies this attempt. A caller polling with the id it was given\ncannot be shown a later request's outcome as though it were its own.","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"started_at":{"format":"date-time","type":["string","null"]},"status":{"description":"pending → running → succeeded | failed","type":"string"}},"required":["profile_id","kind","request_id","status","replace_existing","requested_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/profiles/{profile_id}/hosting":{"get":{"operationId":"profile_hosting_plan","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileHostingPlan"}}},"description":"Hosting plan"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile not found"},"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":"Hosting plan for a profile","tags":["inference"]}}}}
```

## GET /v1/inference/profiles/{profile\_id}/kv-cache

> Live prefix-cache counters, read from the worker. The 30s scrape series is too\
> coarse to attribute to one chat turn.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"KvCacheState":{"description":"What a profile's engine is currently reusing.","properties":{"block_size":{"description":"Tokens per KV block. Reuse happens in whole blocks, so a prompt shorter than two\nof them reports no hits however often it repeats.","format":"int64","type":["integer","null"]},"gpu_blocks":{"format":"int64","type":["integer","null"]},"pod_name":{"description":"Which worker answered, so a caller can tell a restart apart from a\ncounter that merely moved.","type":["string","null"]},"prefix_caching":{"type":["boolean","null"]},"profile_id":{"type":"string"},"queried_tokens":{"description":"Prompt tokens the engine has looked up, cumulatively.","format":"int64","type":"integer"},"reused_tokens":{"description":"Of those, how many skipped prefill because they were already resident.","format":"int64","type":"integer"}},"required":["profile_id","queried_tokens","reused_tokens"],"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/profiles/{profile_id}/kv-cache":{"get":{"operationId":"profile_kv_cache","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KvCacheState"}}},"description":"Live cache counters"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"No worker endpoint known"},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Worker did not answer"},"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":"Live prefix-cache counters, read from the worker. The 30s scrape series is too\ncoarse to attribute to one chat turn.","tags":["inference"]}}}}
```

## GET /v1/inference/profiles/{profile\_id}/progress

> Deployment progress and cold-start timing for a profile

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"DeploymentProgress":{"description":"How far a profile has got, and how long each stage took.","properties":{"activation_started_at":{"format":"date-time","type":["string","null"]},"cold_start_ms":{"description":"Measured activation-start-to-ready, absent until the profile is ready. A\ntime-to-ready, and only a cold start when start_kind is not restore.","format":"int64","type":["integer","null"]},"phase":{"type":["string","null"]},"profile_id":{"type":"string"},"ready":{"type":"boolean"},"ready_at":{"format":"date-time","type":["string","null"]},"restore_checkpoint_path":{"description":"The checkpoint the worker was told to restore from, when it was.","type":["string","null"]},"start_kind":{"description":"How the worker behind this activation started: restore, cold, or null when no\nlive worker pod is known.","type":["string","null"]},"steps":{"items":{"$ref":"#/components/schemas/DeploymentStep"},"type":"array"}},"required":["profile_id","ready","steps"],"type":"object"},"DeploymentStep":{"description":"One recorded step in a profile's deployment, newest first.","properties":{"elapsed_ms":{"description":"Milliseconds since the activation began, so a UI can draw the sequence\nwithout doing date arithmetic. Null when the activation start is unknown.","format":"int64","type":["integer","null"]},"kind":{"description":"Lifecycle kind, e.g. model.weights_ready, model.ready, route.published.","type":"string"},"occurred_at":{"format":"date-time","type":"string"},"payload":{}},"required":["kind","occurred_at","payload"],"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/profiles/{profile_id}/progress":{"get":{"operationId":"get_profile_progress","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeploymentProgress"}}},"description":"Deployment progress"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unknown profile"},"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":"Deployment progress and cold-start timing for a profile","tags":["inference"]}}}}
```

## POST /v1/inference/profiles/{profile\_id}/restart

> Replace this profile's worker so it restores from its last checkpoint, coming back\
> with the KV cache it had in about a minute rather than eleven.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"CheckpointRequestView":{"description":"An on-demand checkpoint request and how far it has got.","properties":{"artifact_id":{"description":"The artifact the checkpoint produced, once it succeeded.","type":["string","null"]},"completed_at":{"format":"date-time","type":["string","null"]},"error":{"description":"Why it failed, in the controller's words.","type":["string","null"]},"kind":{"description":"checkpoint or restart. One row per profile, so asking twice returns the open one.","type":"string"},"profile_id":{"type":"string"},"reason":{"type":["string","null"]},"replace_existing":{"type":"boolean"},"request_id":{"description":"Identifies this attempt. A caller polling with the id it was given\ncannot be shown a later request's outcome as though it were its own.","format":"uuid","type":"string"},"requested_at":{"format":"date-time","type":"string"},"started_at":{"format":"date-time","type":["string","null"]},"status":{"description":"pending → running → succeeded | failed","type":"string"}},"required":["profile_id","kind","request_id","status","replace_existing","requested_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/profiles/{profile_id}/restart":{"post":{"operationId":"restart_profile_worker","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointRequestView"}}},"description":"Restart requested"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Profile not found"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Nothing to restore from"},"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":"Replace this profile's worker so it restores from its last checkpoint, coming back\nwith the KV cache it had in about a minute rather than eleven.","tags":["inference"]}}}}
```

## POST /v1/inference/profiles/{profile\_id}/state

> Set a profile Active or Suspended (capacity intent)

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"SetProfileState":{"properties":{"deadline_ms":{"format":"int64","type":["integer","null"]},"desired_replicas":{"format":"int32","type":["integer","null"]},"desired_state":{"type":"string"}},"required":["desired_state"],"type":"object"},"CapacityIntent":{"properties":{"created_at":{"description":"When this intent row was first created. Not when the request it currently\ndescribes was made: the row is reused for a repeated ask. Use requested_at for that.","format":"date-time","type":"string"},"deadline":{"format":"date-time","type":["string","null"]},"desired_replicas":{"format":"int32","type":"integer"},"desired_state":{"type":"string"},"generation":{"format":"int64","type":"integer"},"id":{"format":"uuid","type":"string"},"profile_id":{"type":"string"},"requested_at":{"description":"When a caller last asked for this exact state and replica count, so it orders\nrequests as they were made rather than as the row happened to change.","format":"date-time","type":"string"},"status":{"type":"string"},"updated_at":{"description":"When this row last changed for any reason, including the expiry sweep. Not an\nordering key for what a caller asked for.","format":"date-time","type":"string"}},"required":["id","profile_id","desired_state","desired_replicas","status","generation","created_at","updated_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/profiles/{profile_id}/state":{"post":{"operationId":"set_profile_state","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetProfileState"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapacityIntent"}}},"description":"Capacity intent accepted"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Set a profile Active or Suspended (capacity intent)","tags":["inference"]}}}}
```

## PUT /v1/inference/profiles/{profile\_id}/worker-endpoint

> Record where a profile's worker publishes its metrics (controller only). The\
> propagator can reach the port but cannot find the pod IP itself.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"ServiceToken":[]}],"components":{"securitySchemes":{"ServiceToken":{"scheme":"bearer","type":"http"}},"schemas":{"ReportWorkerEndpoint":{"description":"Where a profile's worker publishes engine metrics (controller only).","properties":{"metrics_url":{"type":"string"},"pod_name":{"type":["string","null"]}},"required":["metrics_url"],"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/profiles/{profile_id}/worker-endpoint":{"put":{"operationId":"report_worker_endpoint","parameters":[{"in":"path","name":"profile_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportWorkerEndpoint"}}},"required":true},"responses":{"204":{"description":"Recorded"},"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":"Record where a profile's worker publishes its metrics (controller only). The\npropagator can reach the port but cannot find the pod IP itself.","tags":["inference"]}}}}
```

## GET /v1/inference/retention-policies

> List retention policies

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"RetentionPolicy":{"properties":{"enabled":{"type":"boolean"},"max_age_days":{"format":"int64","type":["integer","null"]},"max_count":{"format":"int64","type":["integer","null"]},"min_tier":{"type":["string","null"]},"name":{"type":"string"},"policy_id":{"type":"string"},"profile_id":{"type":["string","null"]}},"required":["policy_id","name","enabled"],"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/retention-policies":{"get":{"operationId":"list_retention_policies","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RetentionPolicy"},"type":"array"}}},"description":"Retention policies"},"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":"List retention policies","tags":["inference"]}}}}
```

## POST /v1/inference/retention-policies

> Create or update a retention policy

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"RetentionPolicyUpsert":{"properties":{"enabled":{"type":"boolean"},"max_age_days":{"format":"int64","type":["integer","null"]},"max_count":{"format":"int64","type":["integer","null"]},"min_tier":{"type":["string","null"]},"name":{"type":"string"},"policy_id":{"type":["string","null"]},"profile_id":{"type":["string","null"]}},"required":["name"],"type":"object"},"RetentionPolicy":{"properties":{"enabled":{"type":"boolean"},"max_age_days":{"format":"int64","type":["integer","null"]},"max_count":{"format":"int64","type":["integer","null"]},"min_tier":{"type":["string","null"]},"name":{"type":"string"},"policy_id":{"type":"string"},"profile_id":{"type":["string","null"]}},"required":["policy_id","name","enabled"],"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/retention-policies":{"post":{"operationId":"upsert_retention_policy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionPolicyUpsert"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetentionPolicy"}}},"description":"Policy saved"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Create or update a retention policy","tags":["inference"]}}}}
```

## DELETE /v1/inference/retention-policies/{policy\_id}

> Delete a retention policy

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"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/retention-policies/{policy_id}":{"delete":{"operationId":"delete_retention_policy","parameters":[{"in":"path","name":"policy_id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Policy deleted"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Not found"},"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":"Delete a retention policy","tags":["inference"]}}}}
```

## GET /v1/inference/routes

> List route policies

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"RoutePolicy":{"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/RouteTarget"},"type":"array"}},"required":["logical_model","mode","queue_timeout_ms","generation","targets"],"type":"object"},"RouteTarget":{"properties":{"priority":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"tier":{"type":"string"}},"required":["profile_id","tier","priority"],"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/routes":{"get":{"operationId":"list_routes","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RoutePolicy"},"type":"array"}}},"description":"List of route policies"},"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":"List route policies","tags":["inference"]}}}}
```

## POST /v1/inference/routes

> Create or update a route policy

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"UpsertRoute":{"properties":{"classifier_profile_id":{"type":["string","null"]},"classifier_prompt":{"type":["string","null"]},"classifier_response_schema":{"type":["string","null"]},"logical_model":{"type":"string"},"mode":{"type":"string"},"queue_timeout_ms":{"format":"int64","type":"integer"},"targets":{"items":{"$ref":"#/components/schemas/UpsertTarget"},"type":"array"}},"required":["logical_model","targets"],"type":"object"},"UpsertTarget":{"properties":{"priority":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"tier":{"type":"string"}},"required":["profile_id","tier","priority"],"type":"object"},"RoutePolicy":{"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/RouteTarget"},"type":"array"}},"required":["logical_model","mode","queue_timeout_ms","generation","targets"],"type":"object"},"RouteTarget":{"properties":{"priority":{"format":"int32","type":"integer"},"profile_id":{"type":"string"},"tier":{"type":"string"}},"required":["profile_id","tier","priority"],"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/routes":{"post":{"operationId":"upsert_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertRoute"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutePolicy"}}},"description":"Route policy saved"},"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":"Create or update a route policy","tags":["inference"]}}}}
```

## POST /v1/inference/routes/simulate

> Project routing outcomes for a traffic mix. A step function on p50, and a profile\
> with nothing measured yet falls back to estimates rather than measurements.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"SimulateRoute":{"properties":{"cold_share":{"format":"double","type":"number"},"deadline_ms":{"format":"int64","type":"integer"},"logical_model":{"type":"string"},"requests_per_hour":{"format":"double","type":"number"},"restore_share":{"format":"double","type":"number"}},"required":["logical_model","requests_per_hour","cold_share","restore_share","deadline_ms"],"type":"object"},"SimulationResult":{"properties":{"cold_share":{"format":"double","type":"number"},"evidence":{"type":"string"},"logical_model":{"type":"string"},"projected_cold_p50_ms":{"format":"double","type":["number","null"]},"projected_deadline_miss_rate":{"format":"double","type":"number"},"projected_fallback_rate":{"format":"double","type":"number"},"projected_p50_ms":{"format":"double","type":"number"},"projected_restore_p50_ms":{"format":"double","type":["number","null"]},"requests_per_hour":{"format":"double","type":"number"},"restore_share":{"format":"double","type":"number"}},"required":["logical_model","requests_per_hour","cold_share","restore_share","projected_fallback_rate","projected_deadline_miss_rate","projected_p50_ms","evidence"],"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/routes/simulate":{"post":{"operationId":"simulate_route","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulateRoute"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationResult"}}},"description":"Projected outcomes"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Unknown logical model"},"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":"Project routing outcomes for a traffic mix. A step function on p50, and a profile\nwith nothing measured yet falls back to estimates rather than measurements.","tags":["inference"]}}}}
```

## GET /v1/inference/routes/status

> Live route-state snapshot per logical model

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"RouteStatusView":{"properties":{"endpoint":{"type":["string","null"]},"fallback_profile_id":{"type":["string","null"]},"fallback_ready":{"type":"boolean"},"logical_model":{"type":"string"},"pending_activation":{"description":"A Pending intent asks for this profile to be Active on at least one replica, so\nsomething is trying to bring it up.","type":"boolean"},"pending_intent":{"description":"Any capacity intent for the primary is still Pending, either direction. Rarely the\nfield you want; prefer pending_activation or pending_release.","type":"boolean"},"pending_release":{"description":"A Pending intent asks for this profile to stop holding an accelerator\n(Suspended, or Active at zero replicas).","type":"boolean"},"primary_phase":{"type":["string","null"]},"primary_profile_id":{"type":"string"},"primary_ready":{"type":"boolean"},"queue_timeout_ms":{"format":"int64","type":"integer"},"restore_checkpoint_path":{"description":"The checkpoint the live worker was told to restore from, when it was.","type":["string","null"]},"start_kind":{"description":"How the worker now on this profile started, read from the pod spec: restore when it\nwas given a checkpoint, cold otherwise.","type":["string","null"]},"state":{"type":"string"}},"required":["logical_model","primary_profile_id","primary_ready","fallback_ready","pending_intent","pending_activation","pending_release","queue_timeout_ms","state"],"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/routes/status":{"get":{"operationId":"route_status","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/RouteStatusView"},"type":"array"}}},"description":"Route-state snapshot"},"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":"Live route-state snapshot per logical model","tags":["inference"]}}}}
```

## GET /v1/inference/startup-comparison

> Cold start against restore, per profile. Measured from the workers that ran, not\
> estimated.

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"ProfileStartupComparison":{"description":"Cold starts against restores, for one profile.","properties":{"cold":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StartLatency"}]},"logical_model":{"type":"string"},"profile_id":{"type":"string"},"restored":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/StartLatency"}]},"saved_ms":{"description":"Milliseconds a restore saves at the median.","format":"int64","type":["integer","null"]},"speedup":{"description":"Cold median divided by restore median. Above 1 means restoring is faster.","format":"double","type":["number","null"]},"starts":{"description":"Every start behind the summaries, newest first, so the numbers can be\nchecked rather than taken on faith.","items":{"$ref":"#/components/schemas/WorkerStart"},"type":"array"}},"required":["profile_id","logical_model","starts"],"type":"object"},"StartLatency":{"properties":{"max_ms":{"format":"int64","type":"integer"},"median_ms":{"format":"int64","type":"integer"},"min_ms":{"format":"int64","type":"integer"},"samples":{"minimum":0,"type":"integer"}},"required":["samples","min_ms","median_ms","max_ms"],"type":"object"},"WorkerStart":{"description":"One worker start, and whether it restored.","properties":{"checkpoint_path":{"type":["string","null"]},"pod_name":{"type":"string"},"ready_at":{"format":"date-time","type":["string","null"]},"restored":{"description":"True when this worker was given a checkpoint to restore from.","type":"boolean"},"start_time_ms":{"description":"PodScheduled to Ready, in milliseconds.","format":"int64","type":"integer"}},"required":["pod_name","start_time_ms","restored"],"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/startup-comparison":{"get":{"operationId":"inference_startup_comparison","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ProfileStartupComparison"},"type":"array"}}},"description":"Cold versus restore worker startup, per profile"},"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":"Cold start against restore, per profile. Measured from the workers that ran, not\nestimated.","tags":["inference"]}}}}
```

## GET /v1/inference/storage/summary

> Per-tier storage summary

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"StorageSummary":{"properties":{"tiers":{"items":{"$ref":"#/components/schemas/StorageTierSummary"},"type":"array"},"total_artifacts":{"format":"int64","type":"integer"},"total_bytes":{"format":"int64","type":"integer"}},"required":["tiers","total_bytes","total_artifacts"],"type":"object"},"StorageTierSummary":{"properties":{"artifacts":{"format":"int64","type":"integer"},"bytes":{"format":"int64","type":"integer"},"residency_hours":{"format":"double","type":"number"},"tier":{"type":"string"},"transfers":{"format":"int64","type":"integer"}},"required":["tier","artifacts","bytes","transfers","residency_hours"],"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/storage/summary":{"get":{"operationId":"storage_summary","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageSummary"}}},"description":"Per-tier storage totals"},"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":"Per-tier storage summary","tags":["inference"]}}}}
```

## GET /v1/inference/usage/series

> Bucketed usage time series

```json
{"openapi":"3.1.0","info":{"title":"Cedana API","version":"0.0.0-dev"},"tags":[{"description":"Cedana inference control plane","name":"inference"}],"security":[{"Token":[]}],"components":{"securitySchemes":{"Token":{"scheme":"bearer","type":"http"}},"schemas":{"UsageBucket":{"properties":{"avg_backend_ms":{"format":"double","type":["number","null"]},"avg_routing_ms":{"format":"double","type":["number","null"]},"avg_ttft_ms":{"format":"double","type":["number","null"]},"bucket":{"format":"date-time","type":"string"},"cold_start_avoided_ms":{"format":"int64","type":"integer"},"completion_tokens":{"format":"int64","type":"integer"},"deadline_misses":{"format":"int64","type":"integer"},"fallbacks":{"format":"int64","type":"integer"},"prompt_tokens":{"format":"int64","type":"integer"},"requests":{"format":"int64","type":"integer"},"successes":{"format":"int64","type":"integer"}},"required":["bucket","requests","fallbacks","successes","deadline_misses","prompt_tokens","completion_tokens","cold_start_avoided_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/usage/series":{"get":{"operationId":"usage_series","parameters":[{"in":"query","name":"hours","required":false,"schema":{"format":"int64","type":"integer"}},{"in":"query","name":"bucket","required":false,"schema":{"type":"string"}},{"in":"query","name":"profile_id","required":false,"schema":{"type":["string","null"]}},{"in":"query","name":"experiment_id","required":false,"schema":{"format":"uuid","type":["string","null"]}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UsageBucket"},"type":"array"}}},"description":"Bucketed usage"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HttpError"}}},"description":"Bad request"},"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":"Bucketed usage time series","tags":["inference"]}}}}
```
