Skip to content

5.7.2.1 Completions

The Completions domain of ai-gateway. Every call to a language model goes through ai-gateway: it holds the provider keys, routes each request by data class and plan tier, checks prompts with Model Armor, reserves and settles the Organization's usage and keeps a ledger of every call without the prompt. Systems call it through the gRPC service of this domain; this REST API is the staff view of the ledger and the providers. It is one API, with its own contract and its own version.

5.7.2.1.1 Versions

Version Status Prod URL Contract
v1 Proposed https://ai-gateway.moonitoring.com/completions/v1 completions/v1/openapi.yaml

The data model has no entities for this domain yet; its schemas are part of the proposal. No entity: ModelCall is the ledger req 69 keeps outside the model, and Provider the state of a provider. The capability ai-gateway.usage.read is proposed. The gateway is called through gRPC; REST is the Console's window.

5.7.2.1.2 Operations

Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.

Operation Request Who Capability
List model calls GET /model-calls Staff ai-gateway.usage.read
Read a model call GET /model-calls/{call_id} Staff ai-gateway.usage.read
List providers GET /providers Staff ai-gateway.usage.read

5.7.2.1.3 gRPC

moochat and grant ask for completions and embeddings; the gateway streams the answer and ends with the usage. grant submits its provider batches through BatchesService, idempotent by request hash, so the provider keys never leave the gateway (D23). The package is moonitoring.ai_gateway.completions.v1: a hyphen is not allowed in a package name.

Service RPC Callers
CompletionsService Complete moochat, grant
CompletionsService Embed moochat, grant
BatchesService SubmitBatch moochat, grant
BatchesService GetBatch moochat, grant

The contract is completions.proto, package moonitoring.ai_gateway.completions.v1:

// Proposed contract, version 1. Status: proposal for review, not confirmed design.
//
// Every call to a language model. The gateway holds the provider keys, routes by data class and plan tier,
// checks the prompt and the answer with Model Armor, reserves usage against the Organization's entitlement before
// the call and settles it after, and writes the ledger. No prompt is stored.
// Callers: moochat (completions of a turn; req 120, 121, 125), grant (OCR and extraction of documents and calls;
// batches through BatchesService, decided 2026-10-31, D23: the provider keys never leave the gateway).
// Deadline: set by the caller, at most 120 s; a stream carries partial answers.
// The callers listed are authentication only (decided 2026-11-11): each RPC below names who may call it and what
// it sees, and refuses anyone else with PERMISSION_DENIED.
// x-moonitoring-callers: moochat, grant
// x-moonitoring-requirements: 120, 121, 125, 69, 205, 206
syntax = "proto3";

package moonitoring.ai_gateway.completions.v1;

service CompletionsService {
  // A chat completion, streamed. The first message of the stream is the routing decision; the last carries usage.
  // Callers: moochat and grant. Sees: the answer to its own request, charged to the Organization it names.
  rpc Complete(CompleteRequest) returns (stream CompleteResponse);
  // Embeddings for texts.
  // Callers: moochat and grant. Sees: the embeddings of the texts it sent.
  rpc Embed(EmbedRequest) returns (EmbedResponse);
}

message CompleteRequest {
  // The caller's request id: the same id in Cloud Logging, in AgentMessage.request_id and in the ledger.
  string request_id = 1;
  // Exactly one of organization_id and moonitoring_user_id: who is metered.
  string organization_id = 2;
  string moonitoring_user_id = 3;
  // The metered feature, e.g. moochat.chat.
  string feature = 4;
  // The AgentModelProfile to use; the gateway resolves provider, model, region and parameters from it.
  string model_profile_id = 5;
  // The highest data class in the prompt; personal goes only to a profile that allows it, in the EU.
  DataClass data_class = 6;
  repeated Message messages = 7;
  // Tools the model may call, as JSON schemas; the caller runs them.
  repeated ToolDefinition tools = 8;
  // Optional overrides within the profile's bounds.
  Parameters parameters = 9;
}

enum DataClass {
  DATA_CLASS_UNSPECIFIED = 0;
  DATA_CLASS_PUBLIC = 1;
  DATA_CLASS_PERSONAL = 2;
}

message Message {
  Role role = 1;
  string content = 2;
  // For a tool result: the call it answers.
  string tool_call_id = 3;
}

enum Role {
  ROLE_UNSPECIFIED = 0;
  ROLE_SYSTEM = 1;
  ROLE_USER = 2;
  ROLE_ASSISTANT = 3;
  ROLE_TOOL = 4;
}

message ToolDefinition {
  string name = 1;
  string description = 2;
  string input_schema_json = 3;
}

message Parameters {
  // Omission keeps the profile value; an explicit zero remains an override within the profile's bounds.
  optional float temperature = 1;
  optional int32 max_output_tokens = 2;
  optional int32 thinking_budget = 3;
}

message CompleteResponse {
  oneof part {
    Routing routing = 1;
    string text_delta = 2;
    ToolCall tool_call = 3;
    Usage usage = 4;
    Blocked blocked = 5;
  }
}

message Routing {
  string provider = 1;
  string model = 2;
  string region = 3;
  string model_profile_id = 4;
}

message ToolCall {
  string id = 1;
  string name = 2;
  string arguments_json = 3;
}

message Usage {
  int32 input_tokens = 1;
  int32 output_tokens = 2;
  int64 cost_micros = 3;
  int32 latency_ms = 4;
  FinishReason finish_reason = 5;
}

enum FinishReason {
  FINISH_REASON_UNSPECIFIED = 0;
  FINISH_REASON_STOP = 1;
  FINISH_REASON_TOOL_CALLS = 2;
  FINISH_REASON_LENGTH = 3;
}

// The call was not made, or its answer withheld.
message Blocked {
  BlockReason reason = 1;
  string detail = 2;
}

enum BlockReason {
  BLOCK_REASON_UNSPECIFIED = 0;
  BLOCK_REASON_LIMIT_REACHED = 1;
  BLOCK_REASON_NOT_ENTITLED = 2;
  BLOCK_REASON_MODEL_ARMOR = 3;
  BLOCK_REASON_DATA_CLASS = 4;
}

// Provider batch jobs (OpenRouter Batch, Gemini Batch) for work that waits hours: the caller journals each request by
// its body hash and the gateway submits once per hash, so a resumed or repeated caller never pays twice.
service BatchesService {
  // Submits a batch of requests to a provider. Idempotent by request_hash: a hash already submitted returns its job.
  rpc SubmitBatch(SubmitBatchRequest) returns (SubmitBatchResponse);
  // Where a batch job stands; when finished, where its answers were written.
  rpc GetBatch(GetBatchRequest) returns (GetBatchResponse);
}

message SubmitBatchRequest {
  // SHA-256 of the exact request body, the identity of the work.
  string request_hash = 1;
  string organization_id = 2;
  string moonitoring_user_id = 3;
  string feature = 4;
  string model_profile_id = 5;
  DataClass data_class = 6;
  // gs:// object holding the batch input in the provider's format; the gateway reads it with its own identity.
  string input_uri = 7;
  // gs:// prefix the gateway writes the answers under, create-only.
  string output_prefix = 8;
}

message SubmitBatchResponse {
  string batch_job_id = 1;
  // True when the hash was already submitted and this is the existing job.
  bool existing = 2;
}

message GetBatchRequest {
  string batch_job_id = 1;
}

message GetBatchResponse {
  string batch_job_id = 1;
  BatchStatus status = 2;
  string provider = 3;
  string provider_job_id = 4;
  string output_uri = 5;
  Usage usage = 6;
  string error = 7;
}

enum BatchStatus {
  BATCH_STATUS_UNSPECIFIED = 0;
  BATCH_STATUS_SUBMITTED = 1;
  BATCH_STATUS_RUNNING = 2;
  BATCH_STATUS_COMPLETED = 3;
  BATCH_STATUS_FAILED = 4;
}

message EmbedRequest {
  string request_id = 1;
  string organization_id = 2;
  string moonitoring_user_id = 3;
  string feature = 4;
  string model_profile_id = 5;
  DataClass data_class = 6;
  repeated string texts = 7;
}

message EmbedResponse {
  repeated Embedding embeddings = 1;
  Usage usage = 2;
}

message Embedding {
  repeated float values = 1;
}

5.7.2.1.4 Contract v1

Proposed version

v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.