{
  "openapi": "3.1.0",
  "info": {
    "title": "gm Gateway API",
    "version": "1.0.0",
    "description": "gm is a privacy-first inference gateway. It is OpenAI-compatible: point an existing OpenAI SDK at this server by setting `base_url` to `https://api.saygm.com/v1` and authenticating with a gm API key, and your code works unchanged. Send a bare model id (no provider prefix) as the `model` field; the gateway resolves the upstream provider from its catalog. Every request is sealed inside an Intel TDX TEE that keeps the route confidential in-transit and in-use. The gateway also exposes the native Anthropic Messages API at `POST /v1/messages` and the Gemini API at `POST /v1beta/models/{model}:generateContent` (base URL `https://api.saygm.com`) for those SDKs. Closed beta."
  },
  "servers": [{ "url": "https://api.saygm.com/v1" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/chat/completions": {
      "post": {
        "operationId": "createChatCompletion",
        "summary": "Create a chat completion",
        "description": "OpenAI-compatible Chat Completions. Set `stream: true` for an incremental Server-Sent Events stream of `chat.completion.chunk` objects terminated by `data: [DONE]`; otherwise a single `chat.completion` object is returned.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ChatCompletionRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "When `stream` is false, a single `chat.completion` JSON object. When `stream` is true, a Server-Sent Events stream (`text/event-stream`) of `chat.completion.chunk` objects terminated by `data: [DONE]`.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ChatCompletion" }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "SSE stream of `chat.completion.chunk` objects, one per `data:` line, terminated by `data: [DONE]`."
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. unknown model).",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "401": {
            "description": "Missing or invalid gm API key.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "402": {
            "description": "Insufficient prepaid balance.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "503": {
            "description": "The requested model has no serving capacity or upstream attempts failed.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, when provided.",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          },
          "429": {
            "description": "The requested model is temporarily cooling or at full concurrency (model_cooling or model_at_capacity).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, capped at 60 seconds.",
                "schema": { "type": "integer", "minimum": 1, "maximum": 60 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          }
        }
      }
    },
    "/responses": {
      "post": {
        "operationId": "createResponse",
        "summary": "Create a response (OpenAI Responses API)",
        "description": "OpenAI-compatible Responses API. Use the OpenAI SDK with `base_url` set to `https://api.saygm.com/v1`; the request and response bodies match the OpenAI Responses schema.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object" } } }
        },
        "responses": {
          "200": {
            "description": "An OpenAI Responses object, or a `text/event-stream` when `stream` is true.",
            "content": {
              "application/json": { "schema": { "type": "object" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": {
            "description": "Invalid request (e.g. unknown model).",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "503": {
            "description": "The requested model has no serving capacity or upstream attempts failed.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, when provided.",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          },
          "429": {
            "description": "The requested model is temporarily cooling or at full concurrency (model_cooling or model_at_capacity).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, capped at 60 seconds.",
                "schema": { "type": "integer", "minimum": 1, "maximum": 60 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          }
        }
      }
    },
    "/credits": {
      "get": {
        "operationId": "getCreditBalance",
        "summary": "Get credit balance",
        "description": "Returns the current spendable prepaid balance for the authenticated gm API key. This is a gm-native endpoint, not part of the OpenAI API. The read is authoritative rather than TTL-cached, so external top-ups are visible immediately.",
        "responses": {
          "200": {
            "description": "The API key's current spendable balance. The response is never cacheable.",
            "headers": {
              "Cache-Control": {
                "description": "Always `no-store`.",
                "schema": { "type": "string", "const": "no-store" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreditBalanceResponse" }
              }
            }
          },
          "401": {
            "description": "Missing, malformed, revoked, or unknown gm API key.",
            "headers": {
              "Cache-Control": {
                "description": "Always `no-store`.",
                "schema": { "type": "string", "const": "no-store" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "503": {
            "description": "The authoritative credit service is unavailable; no stale balance is returned.",
            "headers": {
              "Cache-Control": {
                "description": "Always `no-store`.",
                "schema": { "type": "string", "const": "no-store" }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying when UMS rate-limits the request; omitted otherwise.",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/messages": {
      "post": {
        "operationId": "createMessage",
        "summary": "Create a message (Anthropic Messages API)",
        "description": "Anthropic-compatible Messages API. Use the Anthropic SDK with `base_url` set to `https://api.saygm.com`; the request and response bodies match the Anthropic Messages schema. Auth is still the gm API key as a bearer token.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object" } } }
        },
        "responses": {
          "200": {
            "description": "An Anthropic Messages object, or a `text/event-stream` when `stream` is true.",
            "content": {
              "application/json": { "schema": { "type": "object" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": {
            "description": "Invalid request (e.g. unknown model).",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "503": {
            "description": "The requested model has no serving capacity or upstream attempts failed.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, when provided.",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          },
          "429": {
            "description": "The requested model is temporarily cooling or at full concurrency (model_cooling or model_at_capacity).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, capped at 60 seconds.",
                "schema": { "type": "integer", "minimum": 1, "maximum": 60 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          }
        }
      }
    },
    "/v1beta/models/{modelAndAction}": {
      "servers": [{ "url": "https://api.saygm.com" }],
      "post": {
        "operationId": "geminiGenerateContent",
        "summary": "Gemini generateContent / streamGenerateContent",
        "description": "Gemini-compatible endpoint. `modelAndAction` is the model id and method joined by a colon, e.g. `gemini-2.5-pro:generateContent` or `gemini-2.5-pro:streamGenerateContent`. Use the Google GenAI client with the base URL set to `https://api.saygm.com`. The request and response bodies match the Gemini API schema; auth is the gm API key as a bearer token.",
        "parameters": [
          {
            "name": "modelAndAction",
            "in": "path",
            "required": true,
            "schema": { "type": "string" },
            "example": "gemini-2.5-pro:generateContent"
          }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object" } } }
        },
        "responses": {
          "200": {
            "description": "A Gemini response object, or a `text/event-stream` for `streamGenerateContent`.",
            "content": {
              "application/json": { "schema": { "type": "object" } },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": {
            "description": "Invalid request (e.g. unknown model).",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Error" } }
            }
          },
          "503": {
            "description": "The requested model has no serving capacity or upstream attempts failed.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, when provided.",
                "schema": { "type": "integer", "minimum": 1 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          },
          "429": {
            "description": "The requested model is temporarily cooling or at full concurrency (model_cooling or model_at_capacity).",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying, capped at 60 seconds.",
                "schema": { "type": "integer", "minimum": 1, "maximum": 60 }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/InferenceUnavailableError" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A gm API key minted in the dashboard, sent as `Authorization: Bearer <gm-api-key>`."
      }
    },
    "schemas": {
      "ChatCompletionRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": {
            "type": "string",
            "description": "Bare model id (no provider prefix); the gateway resolves the provider.",
            "examples": ["gpt-5.5", "claude-opus-4-8", "gemini-2.5-pro"]
          },
          "messages": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#/components/schemas/ChatMessage" }
          },
          "stream": {
            "type": "boolean",
            "default": false,
            "description": "Stream the response as Server-Sent Events."
          },
          "temperature": { "type": "number" },
          "max_tokens": { "type": "integer" }
        },
        "additionalProperties": true
      },
      "ChatMessage": {
        "type": "object",
        "required": ["role", "content"],
        "properties": {
          "role": {
            "type": "string",
            "enum": ["system", "user", "assistant", "tool"]
          },
          "content": { "type": "string" }
        }
      },
      "ChatCompletion": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "const": "chat.completion" },
          "created": { "type": "integer" },
          "model": { "type": "string" },
          "choices": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ChatChoice" }
          },
          "usage": { "$ref": "#/components/schemas/Usage" }
        }
      },
      "ChatChoice": {
        "type": "object",
        "properties": {
          "index": { "type": "integer" },
          "message": { "$ref": "#/components/schemas/ChatMessage" },
          "finish_reason": { "type": "string" }
        }
      },
      "Usage": {
        "type": "object",
        "properties": {
          "prompt_tokens": { "type": "integer" },
          "completion_tokens": { "type": "integer" },
          "total_tokens": { "type": "integer" },
          "cost": {
            "type": "number",
            "description": "USD settled against the account for this request — the gateway's settlement figure, not a catalog estimate. Rendered with exactly nine fractional digits."
          },
          "cost_nano_usd": {
            "type": "integer",
            "description": "The same settled amount in nano-USD (10^-9 USD), gm's exact integer accounting unit."
          }
        }
      },
      "CreditBalanceResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["object", "balance"],
        "properties": {
          "object": {
            "type": "string",
            "const": "credit_balance"
          },
          "balance": {
            "$ref": "#/components/schemas/CreditBalance"
          },
          "spent": {
            "allOf": [{ "$ref": "#/components/schemas/CreditSpent" }],
            "description": "This key's consumption in UMS's current billing period (period-to-date, not lifetime spend). Omitted entirely — not a null or zeroed block — when UMS did not report a consumption figure, e.g. shared-balance mode with no per-key budget. Absent means unknown, never zero."
          }
        }
      },
      "CreditBalance": {
        "type": "object",
        "additionalProperties": false,
        "required": ["usd", "nano_usd"],
        "properties": {
          "usd": {
            "type": "string",
            "pattern": "^[0-9]+\\.[0-9]{9}$",
            "description": "Exact decimal USD with nine fractional digits. Keep this as a decimal string when exact accounting matters.",
            "examples": ["12.345678901"]
          },
          "nano_usd": {
            "type": "integer",
            "minimum": 0,
            "description": "The same balance in gm's native integer accounting unit: one nano-USD is 10^-9 USD.",
            "examples": [12345678901]
          }
        }
      },
      "CreditSpent": {
        "type": "object",
        "additionalProperties": false,
        "required": ["usd", "nano_usd"],
        "properties": {
          "usd": {
            "type": "string",
            "pattern": "^[0-9]+\\.[0-9]{9}$",
            "description": "Exact decimal USD with nine fractional digits, same convention as CreditBalance.usd.",
            "examples": ["1.200000000"]
          },
          "nano_usd": {
            "type": "integer",
            "minimum": 0,
            "description": "The same spent figure in gm's native integer accounting unit: one nano-USD is 10^-9 USD.",
            "examples": [1200000000]
          }
        }
      },
      "InferenceUnavailableError": {
        "allOf": [
          { "$ref": "#/components/schemas/Error" },
          {
            "type": "object",
            "properties": {
              "error": {
                "type": "object",
                "properties": {
                  "code": {
                    "description": "Machine-readable failure code. Per-model routing failures use the stable codes model_no_capacity, upstream_unavailable, model_cooling, and model_at_capacity; other service failures carry their own codes, and the Gemini surface returns a numeric code.",
                    "oneOf": [{ "type": "string" }, { "type": "integer" }]
                  }
                }
              }
            }
          }
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": { "type": "string" },
              "type": { "type": "string" },
              "code": { "type": ["string", "integer", "null"] }
            }
          }
        }
      }
    }
  }
}
