{
  "openapi": "3.1.0",
  "info": {
    "title": "Runcrate API",
    "version": "1.0.0",
    "summary": "OpenAI-compatible inference API + GPU infrastructure API.",
    "description": "Runcrate exposes two API surfaces. The inference API at `https://api.runcrate.ai/v1` is OpenAI-compatible: it accepts the standard OpenAI SDK with the base URL changed. The infrastructure API at `https://www.runcrate.ai/api/v1` manages GPU instances, persistent volumes, environments, SSH keys, templates, and billing. Both share a single `rc_live_*` API key.\n\nPricing is per-token, per-image, per-second, or per-minute on the inference API (varies by model; see https://www.runcrate.ai/api/models/catalog for live rates) and per-second on GPU rentals (see https://www.runcrate.ai/pricing for hourly rates per GPU class).\n\nAll infrastructure API responses are wrapped in `{ \"data\": ... }`. List responses also include a `meta` object with pagination cursors. Error responses use `{ \"error\": { \"code\": \"...\", \"message\": \"...\" } }`.",
    "termsOfService": "https://www.runcrate.ai/terms",
    "contact": { "name": "Runcrate", "url": "https://www.runcrate.ai/contact" },
    "license": { "name": "Proprietary", "url": "https://www.runcrate.ai/terms" }
  },
  "servers": [
    { "url": "https://api.runcrate.ai/v1", "description": "Inference API (OpenAI-compatible)" },
    { "url": "https://www.runcrate.ai/api/v1", "description": "Infrastructure API (instances, storage, environments, ssh-keys, templates, billing)" }
  ],
  "x-runcrate-platform": {
    "homepage": "https://www.runcrate.ai",
    "docs": "https://www.runcrate.ai/docs/getting-started/introduction",
    "pricing": {
      "inference": "https://www.runcrate.ai/inference/pricing",
      "gpu": "https://www.runcrate.ai/pricing",
      "modelCatalog": "https://www.runcrate.ai/api/models/catalog"
    },
    "sdks": {
      "typescript": "https://www.npmjs.com/package/@runcrate/sdk",
      "aiSdkProvider": "https://www.npmjs.com/package/@runcrate/ai"
    },
    "openaiCompatibility": "Drop-in replacement for the OpenAI Python and TypeScript SDKs. Set `base_url=https://api.runcrate.ai/v1` and existing code keeps working."
  },
  "security": [{ "ApiKeyAuth": [] }],
  "tags": [
    { "name": "Chat", "description": "OpenAI-compatible chat completions." },
    { "name": "Images", "description": "Text-to-image generation." },
    { "name": "Videos", "description": "Async text-to-video and image-to-video generation." },
    { "name": "Audio", "description": "Text-to-speech and speech-to-text." },
    { "name": "Embeddings", "description": "Vector embeddings for RAG and search." },
    { "name": "Models", "description": "Model catalog discovery." },
    { "name": "Instances", "description": "GPU instance lifecycle." },
    { "name": "Storage", "description": "Persistent volume management." },
    { "name": "Environments", "description": "Resource isolation containers within a workspace." },
    { "name": "SSH Keys", "description": "SSH key management for instance access." },
    { "name": "Templates", "description": "Pre-built instance images and configurations." },
    { "name": "Billing", "description": "Credit balance, transactions, usage metrics." }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Use a Runcrate API key with the `rc_live_*` prefix as the bearer token. Create one at https://www.runcrate.ai/dashboard/api-keys."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "message"],
            "properties": {
              "code": { "type": "string", "description": "Machine-readable error code (e.g. `validation_error`, `unauthorized`, `not_found`, `insufficient_credits`, `rate_limited`, `internal_error`)." },
              "message": { "type": "string", "description": "Human-readable error message." },
              "details": { "type": "object", "additionalProperties": true, "description": "Optional structured error context." }
            }
          }
        }
      },
      "ListMeta": {
        "type": "object",
        "description": "Pagination metadata on list responses.",
        "properties": {
          "cursor": { "type": "string", "nullable": true },
          "hasMore": { "type": "boolean", "nullable": true },
          "total": { "type": "integer", "nullable": true },
          "requestId": { "type": "string", "nullable": true }
        }
      },
      "ChatMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": { "type": "string", "enum": ["system", "user", "assistant", "tool"] },
          "name": { "type": "string" },
          "content": {
            "oneOf": [
              { "type": "string" },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": { "type": "string", "enum": ["text", "image_url"] },
                    "text": { "type": "string" },
                    "image_url": {
                      "type": "object",
                      "properties": { "url": { "type": "string", "format": "uri" } }
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": { "type": "string", "description": "Model id from the catalog (e.g. `deepseek/deepseek-v3.2`)." },
          "messages": { "type": "array", "items": { "$ref": "#/components/schemas/ChatMessage" } },
          "max_tokens": { "type": "integer", "minimum": 1 },
          "temperature": { "type": "number", "minimum": 0, "maximum": 2 },
          "top_p": { "type": "number", "minimum": 0, "maximum": 1 },
          "stop": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] },
          "frequency_penalty": { "type": "number", "minimum": -2, "maximum": 2 },
          "presence_penalty": { "type": "number", "minimum": -2, "maximum": 2 },
          "stream": { "type": "boolean", "default": false },
          "tools": { "type": "array", "items": { "type": "object" } },
          "tool_choice": { "oneOf": [{ "type": "string" }, { "type": "object" }] },
          "response_format": { "type": "object" }
        }
      },
      "ChatCompletionResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "enum": ["chat.completion"] },
          "created": { "type": "integer" },
          "model": { "type": "string" },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": { "type": "integer" },
                "message": { "$ref": "#/components/schemas/ChatMessage" },
                "finish_reason": { "type": "string", "enum": ["stop", "length", "tool_calls", "content_filter"] }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": { "type": "integer" },
              "completion_tokens": { "type": "integer" },
              "total_tokens": { "type": "integer" }
            }
          }
        }
      },
      "ImageGenerationRequest": {
        "type": "object",
        "required": ["model", "prompt"],
        "properties": {
          "model": { "type": "string", "description": "Image model id (e.g. `black-forest-labs/FLUX.1.1-pro`)." },
          "prompt": { "type": "string" },
          "width": { "type": "integer", "minimum": 256, "maximum": 2048 },
          "height": { "type": "integer", "minimum": 256, "maximum": 2048 },
          "aspect_ratio": { "type": "string", "example": "16:9" },
          "num_inference_steps": { "type": "integer", "minimum": 1, "maximum": 100 },
          "guidance": { "type": "number" },
          "response_format": { "type": "string", "enum": ["url", "b64_json"], "default": "url" }
        }
      },
      "ImageGenerationResponse": {
        "type": "object",
        "properties": {
          "created": { "type": "integer" },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": { "type": "string", "format": "uri" },
                "b64_json": { "type": "string" }
              }
            }
          }
        }
      },
      "VideoGenerationRequest": {
        "type": "object",
        "required": ["model", "prompt"],
        "properties": {
          "model": { "type": "string", "description": "Video model id (e.g. `openai/sora-2`)." },
          "prompt": { "type": "string" },
          "duration_seconds": { "type": "integer", "description": "Seconds; varies by model." },
          "image_url": { "type": "string", "format": "uri", "description": "Optional image-to-video reference." },
          "aspect_ratio": { "type": "string", "example": "16:9" }
        }
      },
      "VideoJobSubmit": {
        "type": "object",
        "required": ["id", "status"],
        "properties": {
          "id": { "type": "string", "description": "Job id to poll." },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "failed"] }
        }
      },
      "VideoJobStatus": {
        "type": "object",
        "required": ["id", "status"],
        "properties": {
          "id": { "type": "string" },
          "status": { "type": "string", "enum": ["queued", "processing", "completed", "failed"] },
          "error": { "type": "string", "description": "Failure reason when `status=failed`." }
        }
      },
      "SpeechRequest": {
        "type": "object",
        "required": ["model", "input"],
        "properties": {
          "model": { "type": "string", "example": "Qwen/Qwen3-TTS" },
          "input": { "type": "string" },
          "voice": { "type": "string", "example": "alloy" },
          "response_format": { "type": "string", "enum": ["mp3", "wav", "opus", "flac"], "default": "mp3" },
          "speed": { "type": "number", "minimum": 0.25, "maximum": 4.0 }
        }
      },
      "TranscriptionResponse": {
        "type": "object",
        "required": ["text"],
        "properties": {
          "text": { "type": "string" },
          "duration": { "type": "number", "description": "verbose_json only. Audio duration in seconds." },
          "language": { "type": "string", "nullable": true, "description": "verbose_json only. Detected language code." },
          "segments": {
            "type": "array",
            "nullable": true,
            "description": "verbose_json only. Timed segments of the transcript.",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "integer" },
                "start": { "type": "number", "description": "Seconds from the start of the audio." },
                "end": { "type": "number", "description": "Seconds from the start of the audio." },
                "text": { "type": "string" }
              }
            }
          }
        }
      },
      "EmbeddingRequest": {
        "type": "object",
        "required": ["model", "input"],
        "properties": {
          "model": { "type": "string" },
          "input": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] },
          "encoding_format": { "type": "string", "enum": ["float", "base64"], "default": "float" }
        }
      },
      "EmbeddingResponse": {
        "type": "object",
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "object": { "type": "string", "enum": ["embedding"] },
                "index": { "type": "integer" },
                "embedding": { "type": "array", "items": { "type": "number" } }
              }
            }
          },
          "model": { "type": "string" },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": { "type": "integer" },
              "total_tokens": { "type": "integer" }
            }
          }
        }
      },
      "ModelListResponse": {
        "type": "object",
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "object": { "type": "string", "enum": ["model"] },
                "created": { "type": "integer" },
                "owned_by": { "type": "string" }
              }
            }
          }
        }
      },
      "EnvVar": {
        "type": "object",
        "required": ["key", "value"],
        "properties": {
          "key": { "type": "string" },
          "value": { "type": "string" }
        }
      },
      "Instance": {
        "type": "object",
        "required": ["id", "name", "status"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "status": {
            "type": "string",
            "enum": ["running", "starting", "deploying", "error", "terminated"],
            "description": "Public lifecycle status. `starting` covers initial provisioning queue; `deploying` is the active boot phase; `running` means SSH-reachable; `error` is unrecoverable failure; `terminated` is post-delete."
          },
          "gpu_type": { "type": "string", "nullable": true, "description": "GPU model id (e.g. `h100-sxm`)." },
          "gpu_count": { "type": "integer", "nullable": true },
          "cpu_cores": { "type": "integer", "nullable": true },
          "memory": { "type": "integer", "nullable": true, "description": "GB" },
          "storage": { "type": "integer", "nullable": true, "description": "GB" },
          "region": { "type": "string", "nullable": true },
          "ip": { "type": "string", "nullable": true, "description": "Public IP / SSH host once status=running." },
          "os_image": { "type": "string", "nullable": true },
          "cost_per_hour": { "type": "number", "nullable": true },
          "deployed_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "InstanceCreateRequest": {
        "type": "object",
        "required": ["name"],
        "description": "Provide either `gpu_type` (Runcrate picks an available configuration for that GPU) or `instance_type_id` (specific config from `/instances/types`).",
        "properties": {
          "name": { "type": "string", "description": "Human-readable instance name." },
          "gpu_type": { "type": "string", "description": "GPU model id (e.g. `h100-sxm`). Required if `instance_type_id` is not provided." },
          "instance_type_id": { "type": "string", "description": "Exact instance-type id from `GET /instances/types`. Required if `gpu_type` is not provided." },
          "region": { "type": "string", "description": "Only launch in this region: a `region` from `GET /instances/types`, the start of one (`us-east`), or a city or country (`canada`). If nothing is available there the request fails and names the regions that have it; it never launches elsewhere. Defaults to `auto` (any region)." },
          "gpu_count": { "type": "integer", "minimum": 1 },
          "cpu_cores": { "type": "integer", "minimum": 1 },
          "memory": { "type": "integer", "description": "GB", "minimum": 1 },
          "storage": { "type": "integer", "description": "GB ephemeral storage", "minimum": 1 },
          "template": { "type": "string", "description": "Template id to boot from." },
          "ssh_key_id": { "type": "string", "description": "ID of an SSH key to inject (create one via POST /ssh-keys)." },
          "env_vars": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/EnvVar" },
            "description": "Environment variables to inject. Each item must be `{ \"key\": \"NAME\", \"value\": \"...\" }`."
          },
          "startup_commands": { "type": "array", "items": { "type": "string" } },
          "storage_id": { "type": "string", "description": "Persistent volume to attach at boot. Mounts at `/workspace`." },
          "launch_script": { "type": "string", "description": "Raw shell script to run on boot." },
          "launch_script_base64": { "type": "string", "description": "Base64-encoded launch script (alternative to `launch_script`)." }
        }
      },
      "InstanceStatusResponse": {
        "type": "object",
        "required": ["id", "status"],
        "properties": {
          "id": { "type": "string" },
          "status": { "type": "string", "enum": ["running", "starting", "deploying", "error", "terminated"] },
          "ip": { "type": "string", "nullable": true }
        }
      },
      "InstanceType": {
        "type": "object",
        "required": ["id", "gpu_type", "gpu_count", "cpu_cores", "memory_gb", "storage_gb", "region", "hourly_rate"],
        "properties": {
          "id": { "type": "string", "description": "Opaque slug like `bold-tesla-a6000-fa6f`. Pass to `instance_type_id` when creating an instance." },
          "gpu_type": { "type": "string" },
          "gpu_count": { "type": "integer" },
          "cpu_cores": { "type": "integer" },
          "memory_gb": { "type": "integer" },
          "storage_gb": { "type": "integer" },
          "region": { "type": "string" },
          "deployment_type": { "type": "string", "nullable": true },
          "hourly_rate": { "type": "number", "description": "USD per hour." }
        }
      },
      "Environment": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "is_default": { "type": "boolean", "nullable": true },
          "created_at": { "type": "string", "format": "date-time", "nullable": true },
          "updated_at": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "EnvironmentCreateRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "description": "Lowercase letters, numbers, and dashes only (1–32 chars), starting with a letter or number.",
            "pattern": "^[a-z0-9][a-z0-9-]{0,31}$"
          }
        }
      },
      "EnvironmentUpdateRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,31}$" },
          "is_default": { "type": "boolean" }
        }
      },
      "SSHKey": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "fingerprint": { "type": "string", "nullable": true },
          "type": { "type": "string", "nullable": true, "description": "Key type (ssh-rsa, ssh-ed25519, etc.)." },
          "createdAt": { "type": "string", "format": "date-time", "nullable": true },
          "lastUsed": { "type": "string", "format": "date-time", "nullable": true },
          "projectId": { "type": "string", "nullable": true }
        }
      },
      "SSHKeyCreateRequest": {
        "type": "object",
        "required": ["name", "public_key"],
        "properties": {
          "name": { "type": "string" },
          "public_key": { "type": "string", "description": "OpenSSH public key string." },
          "type": { "type": "string", "description": "Key type (auto-detected if omitted)." }
        }
      },
      "StorageVolume": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "sizeGb": { "type": "integer", "nullable": true },
          "status": { "type": "string", "nullable": true },
          "region": { "type": "string", "nullable": true },
          "providerType": { "type": "string", "nullable": true },
          "deploymentId": { "type": "string", "nullable": true, "description": "Instance currently mounting this volume. Volume mounts at `/workspace` inside the instance." },
          "projectId": { "type": "string", "nullable": true },
          "environmentId": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time", "nullable": true },
          "updatedAt": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "StorageCreateRequest": {
        "type": "object",
        "required": ["name", "size_gb", "region"],
        "properties": {
          "name": { "type": "string" },
          "size_gb": { "type": "integer", "minimum": 10, "maximum": 10000, "description": "Size in GB. Must be between 10 and 10000." },
          "region": { "type": "string" }
        }
      },
      "StorageResizeRequest": {
        "type": "object",
        "required": ["size_gb"],
        "properties": {
          "size_gb": { "type": "integer", "minimum": 10, "maximum": 10000, "description": "New size in GB. Must be greater than current size." }
        }
      },
      "StorageDeleteResult": {
        "type": "object",
        "required": ["message"],
        "properties": {
          "message": { "type": "string" },
          "refund_amount": { "type": "number", "description": "Credit refunded for unused time, if any." }
        }
      },
      "StorageRegion": {
        "type": "object",
        "required": ["id", "name", "provider"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "provider": { "type": "string" }
        }
      },
      "Template": {
        "type": "object",
        "required": ["id", "name"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "description": { "type": "string", "nullable": true },
          "category": { "type": "string", "nullable": true }
        }
      },
      "Balance": {
        "type": "object",
        "required": ["creditsBalance", "activeUsageCost"],
        "properties": {
          "creditsBalance": { "type": "number", "description": "Available prepaid credit balance in USD." },
          "activeUsageCost": { "type": "number", "description": "Currently accruing cost from running instances + active jobs." }
        }
      },
      "Transaction": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": { "type": "string" },
          "projectId": { "type": "string", "nullable": true },
          "type": { "type": "string", "nullable": true, "enum": [null, "credit", "usage", "refund", "adjustment"] },
          "amount": { "type": "number", "nullable": true, "description": "USD. Positive values are credits added; negative values are usage charges." },
          "description": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "UsageSummary": {
        "type": "object",
        "properties": {
          "total_requests": { "type": "integer", "nullable": true },
          "total_prompt_tokens": { "type": "integer", "nullable": true },
          "total_completion_tokens": { "type": "integer", "nullable": true },
          "total_tokens": { "type": "integer", "nullable": true },
          "total_cost": { "type": "number", "nullable": true, "description": "USD." }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request (missing fields, bad parameters).",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "ValidationError": {
        "description": "Request shape or values failed validation.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "Authenticated but not permitted for this resource.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "PaymentRequired": {
        "description": "Insufficient credits.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Conflict": {
        "description": "Conflict with existing resource (e.g. duplicate name).",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Rate limited. Retry with exponential backoff.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  },
  "paths": {
    "/chat/completions": {
      "post": {
        "summary": "Chat / LLM completion",
        "description": "OpenAI-compatible chat completion endpoint. Drop-in replacement for `OpenAI(base_url='https://api.runcrate.ai/v1')`.",
        "operationId": "createChatCompletion",
        "tags": ["Chat"],
        "x-runcrate-pricing": {
          "model": "per_1m_tokens",
          "currency": "USD",
          "billable_by": "input_tokens + output_tokens (billed separately at model-specific rates)",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatCompletionRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Completion (or SSE stream when stream=true).",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ChatCompletionResponse" } },
              "text/event-stream": { "schema": { "type": "string", "description": "Server-sent event stream of OpenAI-compatible chunks." } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/images/generations": {
      "post": {
        "summary": "Image generation",
        "description": "Generate images with FLUX, Stable Diffusion 3.5, Ideogram, Seedream, and other image models.",
        "operationId": "createImage",
        "tags": ["Images"],
        "x-runcrate-pricing": {
          "model": "per_image",
          "currency": "USD",
          "billable_by": "successful image generation",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageGenerationRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Image URLs or base64 payloads.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageGenerationResponse" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/videos": {
      "post": {
        "summary": "Submit video generation job",
        "description": "Async: returns the job id. Poll `GET /videos/{id}` for status, then download via `GET /videos/{id}/download` once `status=completed`. Provider URLs are never exposed; the download endpoint is the only way to fetch the MP4.",
        "operationId": "createVideoJob",
        "tags": ["Videos"],
        "x-runcrate-pricing": {
          "model": "per_second",
          "currency": "USD",
          "billable_by": "seconds of generated video",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VideoGenerationRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Video job queued. Poll `GET /videos/{id}` for status.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VideoJobSubmit" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/videos/{id}": {
      "get": {
        "summary": "Poll a video generation job",
        "description": "Returns the current job status. When `status=completed`, fetch the MP4 via `GET /videos/{id}/download`. The underlying provider URL is never exposed.",
        "operationId": "getVideoJob",
        "tags": ["Videos"],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Job status.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VideoJobStatus" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/videos/{id}/download": {
      "get": {
        "summary": "Download generated video",
        "description": "Stream the MP4 directly. Only valid when the job's `status=completed`.",
        "operationId": "downloadVideo",
        "tags": ["Videos"],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "MP4 binary.",
            "content": { "video/mp4": { "schema": { "type": "string", "format": "binary" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "description": "Job not yet complete." }
        }
      }
    },
    "/audio/speech": {
      "post": {
        "summary": "Text-to-speech",
        "description": "Synthesize speech with Qwen3-TTS, Kokoro, Orpheus, and other voice models. Returns audio binary.",
        "operationId": "createSpeech",
        "tags": ["Audio"],
        "x-runcrate-pricing": {
          "model": "per_1k_chars",
          "currency": "USD",
          "billable_by": "characters in input",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SpeechRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Audio binary in the requested format.",
            "content": {
              "audio/mpeg": { "schema": { "type": "string", "format": "binary" } },
              "audio/wav": { "schema": { "type": "string", "format": "binary" } },
              "audio/ogg": { "schema": { "type": "string", "format": "binary" } },
              "audio/flac": { "schema": { "type": "string", "format": "binary" } }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/audio/transcriptions": {
      "post": {
        "summary": "Speech-to-text",
        "description": "Transcribe audio with Whisper Large V3, Voxtral, and other ASR models. Multipart form upload.",
        "operationId": "createTranscription",
        "tags": ["Audio"],
        "x-runcrate-pricing": {
          "model": "per_minute",
          "currency": "USD",
          "billable_by": "minutes of audio",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file", "model"],
                "properties": {
                  "file": { "type": "string", "format": "binary", "description": "Audio file (mp3, wav, m4a, flac, webm, mp4)." },
                  "model": { "type": "string", "example": "openai/whisper-large-v3" },
                  "language": { "type": "string", "description": "Optional hint for the spoken language as an ISO-639-1 code (e.g. 'en'; 'en-US' is read as 'en'). Unrecognised values are ignored and the language is detected, as when it is omitted." },
                  "response_format": {
                    "type": "string",
                    "enum": ["json", "verbose_json", "text", "srt", "vtt"],
                    "default": "verbose_json",
                    "description": "Omitted: the full object (text, duration, language, segments), the same as verbose_json. json returns only {text}, as OpenAI does. text, srt and vtt return text/plain (the transcript, SubRip subtitles, WebVTT subtitles). Any other value returns 400. Billing is per minute of audio for every format."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The transcription, shaped by response_format.",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/TranscriptionResponse" } },
              "text/plain": {
                "schema": { "type": "string" },
                "example": "1\n00:00:00,000 --> 00:00:02,500\nHello, welcome to Runcrate!\n"
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/embeddings": {
      "post": {
        "summary": "Create embeddings",
        "description": "Vector embeddings for RAG, semantic search, and classification. OpenAI-compatible.",
        "operationId": "createEmbedding",
        "tags": ["Embeddings"],
        "x-runcrate-pricing": {
          "model": "per_1m_tokens",
          "currency": "USD",
          "billable_by": "input tokens",
          "live_rates": "https://www.runcrate.ai/api/models/catalog"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmbeddingRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Embedding vectors.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmbeddingResponse" } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/models": {
      "get": {
        "summary": "List available models",
        "description": "OpenAI-compatible model list. For full pricing, parameters, and supported_parameters, query https://www.runcrate.ai/api/models/catalog.",
        "operationId": "listModels",
        "tags": ["Models"],
        "responses": {
          "200": {
            "description": "Model list.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelListResponse" } } }
          }
        }
      }
    },
    "/instances": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List instances",
        "operationId": "listInstances",
        "tags": ["Instances"],
        "parameters": [
          { "name": "search", "in": "query", "required": false, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Instance list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Instance" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "summary": "Create a GPU instance",
        "description": "Provision a dedicated GPU instance. Most instances are running within a few minutes. Specify either `gpu_type` (auto-deploy) or `instance_type_id` (specific config from `/instances/types`).",
        "operationId": "createInstance",
        "tags": ["Instances"],
        "x-runcrate-pricing": {
          "model": "per_second",
          "currency": "USD",
          "billable_by": "running time of the instance, billed per second from start to terminate",
          "live_rates_per_gpu": {
            "rtx-4090": "https://www.runcrate.ai/pricing/gpu/rtx-4090",
            "rtx-5090": "https://www.runcrate.ai/pricing/gpu/rtx-5090",
            "a100-pcie": "https://www.runcrate.ai/pricing/gpu/a100-pcie",
            "a100-sxm": "https://www.runcrate.ai/pricing/gpu/a100-sxm",
            "h100-pcie": "https://www.runcrate.ai/pricing/gpu/h100-pcie",
            "h100-sxm": "https://www.runcrate.ai/pricing/gpu/h100-sxm",
            "h200": "https://www.runcrate.ai/pricing/gpu/h200",
            "b200": "https://www.runcrate.ai/pricing/gpu/b200",
            "gb200": "https://www.runcrate.ai/pricing/gpu/gb200",
            "gb300": "https://www.runcrate.ai/pricing/gpu/gb300",
            "mi300x": "https://www.runcrate.ai/pricing/gpu/mi300x"
          }
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstanceCreateRequest" } } }
        },
        "responses": {
          "201": {
            "description": "Instance created. Status will be `starting` or `deploying` until ready.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Instance" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/instances/{id}": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get instance",
        "operationId": "getInstance",
        "tags": ["Instances"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Instance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Instance" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "summary": "Terminate instance",
        "description": "Stops and deallocates the instance. Billing stops at termination time.",
        "operationId": "deleteInstance",
        "tags": ["Instances"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "204": { "description": "Instance terminated." },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/instances/{id}/status": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get instance status",
        "description": "Lightweight status poll: returns just the status field and IP. Cheaper than fetching the full instance.",
        "operationId": "getInstanceStatus",
        "tags": ["Instances"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Instance status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/InstanceStatusResponse" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/instances/types": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List available instance types",
        "description": "Concrete combinations of GPU + count + region currently available. Use the `id` here as `instance_type_id` when creating an instance.",
        "operationId": "listInstanceTypes",
        "tags": ["Instances"],
        "parameters": [
          { "name": "gpu_type", "in": "query", "schema": { "type": "string" } },
          { "name": "region", "in": "query", "schema": { "type": "string" } },
          { "name": "gpu_count", "in": "query", "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": {
            "description": "Instance types sorted by price ascending.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/InstanceType" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/storage": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List persistent volumes",
        "operationId": "listStorage",
        "tags": ["Storage"],
        "parameters": [{ "name": "search", "in": "query", "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Volumes.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/StorageVolume" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create persistent volume",
        "description": "Persistent volumes outlive instances and mount at `/workspace` inside instances. Use the same volume across runs to keep weights and datasets warm.",
        "operationId": "createStorage",
        "tags": ["Storage"],
        "x-runcrate-pricing": {
          "model": "per_gb_per_month",
          "currency": "USD",
          "live_rates": "https://www.runcrate.ai/pricing"
        },
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageCreateRequest" } } }
        },
        "responses": {
          "201": {
            "description": "Volume created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/StorageVolume" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      }
    },
    "/storage/{id}": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get persistent volume",
        "operationId": "getStorage",
        "tags": ["Storage"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Volume.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/StorageVolume" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "summary": "Resize persistent volume",
        "description": "Increase a volume's size. Cannot shrink. Pro-rated billing applies for the size delta.",
        "operationId": "resizeStorage",
        "tags": ["Storage"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StorageResizeRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Resized volume.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/StorageVolume" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "402": { "$ref": "#/components/responses/PaymentRequired" }
        }
      },
      "delete": {
        "summary": "Delete persistent volume",
        "description": "Permanent. Returns any pro-rated refund.",
        "operationId": "deleteStorage",
        "tags": ["Storage"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Deletion result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/StorageDeleteResult" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/storage/regions": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List storage regions",
        "operationId": "listStorageRegions",
        "tags": ["Storage"],
        "responses": {
          "200": {
            "description": "Regions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/StorageRegion" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/environments": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List environments",
        "description": "Environments are resource-isolation containers within a workspace. Money lives at the workspace level; resources (instances, storage, API keys) live in environments.",
        "operationId": "listEnvironments",
        "tags": ["Environments"],
        "responses": {
          "200": {
            "description": "Environments.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Environment" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create environment",
        "description": "Only workspace owners and admins can create environments.",
        "operationId": "createEnvironment",
        "tags": ["Environments"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnvironmentCreateRequest" } } }
        },
        "responses": {
          "201": {
            "description": "Environment created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Environment" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/environments/{id}": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get environment",
        "operationId": "getEnvironment",
        "tags": ["Environments"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": {
            "description": "Environment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Environment" } }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "summary": "Update environment",
        "description": "Rename or change the default flag.",
        "operationId": "updateEnvironment",
        "tags": ["Environments"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnvironmentUpdateRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Environment updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Environment" } }
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete environment",
        "description": "The `main` environment cannot be deleted. Cannot delete an environment that still has active deployments, storage volumes, or API keys.",
        "operationId": "deleteEnvironment",
        "tags": ["Environments"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "204": { "description": "Environment deleted." },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/ssh-keys": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List SSH keys",
        "operationId": "listSSHKeys",
        "tags": ["SSH Keys"],
        "responses": {
          "200": {
            "description": "SSH keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/SSHKey" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add SSH key",
        "description": "Upload an OpenSSH public key. Returns the key id used as `ssh_key_id` when creating instances.",
        "operationId": "createSSHKey",
        "tags": ["SSH Keys"],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SSHKeyCreateRequest" } } }
        },
        "responses": {
          "201": {
            "description": "SSH key created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/SSHKey" } }
                }
              }
            }
          },
          "409": { "$ref": "#/components/responses/Conflict" }
        }
      }
    },
    "/ssh-keys/{id}": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "delete": {
        "summary": "Delete SSH key",
        "operationId": "deleteSSHKey",
        "tags": ["SSH Keys"],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "204": { "description": "Key deleted." },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/templates": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List instance templates",
        "description": "Pre-baked images / configurations (vLLM, Comfy, Jupyter, Axolotl, etc.). Pass the template id to `POST /instances` to skip dependency setup.",
        "operationId": "listTemplates",
        "tags": ["Templates"],
        "parameters": [
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "page_size", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } },
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "category", "in": "query", "schema": { "type": "string" } },
          { "name": "sort_by", "in": "query", "schema": { "type": "string", "enum": ["created_at", "name", "category", "updated_at"] } },
          { "name": "sort_dir", "in": "query", "schema": { "type": "string", "enum": ["asc", "desc"] } }
        ],
        "responses": {
          "200": {
            "description": "Templates.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Template" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/billing/balance": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get credit balance",
        "description": "Returns prepaid credit balance and currently-accruing usage cost.",
        "operationId": "getBalance",
        "tags": ["Billing"],
        "responses": {
          "200": {
            "description": "Balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/Balance" } }
                }
              }
            }
          }
        }
      }
    },
    "/billing/transactions": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "List billing transactions",
        "description": "Credit purchases, usage charges, refunds, and admin adjustments.",
        "operationId": "listTransactions",
        "tags": ["Billing"],
        "parameters": [
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
          { "name": "type", "in": "query", "schema": { "type": "string", "enum": ["credit", "usage", "refund", "adjustment"] } }
        ],
        "responses": {
          "200": {
            "description": "Transactions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Transaction" } },
                    "meta": { "$ref": "#/components/schemas/ListMeta" }
                  }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    },
    "/billing/usage": {
      "servers": [{ "url": "https://www.runcrate.ai/api/v1" }],
      "get": {
        "summary": "Get usage summary",
        "description": "Aggregate usage metrics over a date range. Pass `from` and `to` as ISO-8601 dates.",
        "operationId": "getUsage",
        "tags": ["Billing"],
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": {
          "200": {
            "description": "Usage summary.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["data"],
                  "properties": { "data": { "$ref": "#/components/schemas/UsageSummary" } }
                }
              }
            }
          },
          "422": { "$ref": "#/components/responses/ValidationError" }
        }
      }
    }
  }
}
