Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API examples

Every public endpoint, with real requests and responses captured from Model Gateway’s own code. The full endpoint list is in the generated API reference. Authentication says what a caller needs.

Base URL: https://gqbzygqa4dd3t54xnb2fg5wcou0pitmm.lambda-url.us-east-1.on.aws. Bodies are JSON (Content-Type: application/json); times are RFC 3339 in UTC. $AUTH below stands for:

AUTH=(-H "Authorization: Bearer $CHIRPAUTH_MACHINE_TOKEN"
      -H "x-user-id: u_8Q3K2M11XZ"
      -H "x-granite-grant: b6ddef35-fe77-43be-a871-bb80d528906a")

The examples act for a person whose Granite id is gr_sub_alice.

Provider credentials

Add a credential

POST /v1/model-gateway/provider-credentials

curl https://gqbzygqa4dd3t54xnb2fg5wcou0pitmm.lambda-url.us-east-1.on.aws/v1/model-gateway/provider-credentials \
  "${AUTH[@]}" -H "Content-Type: application/json" \
  -d '{"provider": "anthropic", "label": "My Anthropic key", "api_key": "sk-ant-example-0000-wxyz"}'
FieldRequiredRules
providerYes1–128 characters, no control characters, not fake. A built-in provider or one of the person’s custom adapters; see Concepts.
api_keyYes8–4096 characters, no control characters.
labelNo1–128 characters. Defaults to provider.

Model Gateway does not check the key with the provider. A credential for a custom adapter also has destination (the adapter’s dialect, base_url and auth_style, copied now); a built-in provider’s has none.

Response, 201 Created:

{
  "credential": {
    "created_at": "2026-11-05T20:41:21.618254305Z",
    "id": "c521b434-5993-4eca-83c9-5b15d20523d6",
    "key_hint": "...wxyz",
    "label": "My Anthropic key",
    "owner_uid": "gr_sub_alice",
    "provider": "anthropic",
    "updated_at": "2026-11-05T20:41:21.618254305Z"
  }
}

List credentials

GET /v1/model-gateway/provider-credentials returns the person’s credentials in the same shape, without the credential wrapper:

[
  {
    "created_at": "2026-11-05T20:41:21.618254305Z",
    "id": "c521b434-5993-4eca-83c9-5b15d20523d6",
    "key_hint": "...wxyz",
    "label": "My Anthropic key",
    "owner_uid": "gr_sub_alice",
    "provider": "anthropic",
    "updated_at": "2026-11-05T20:41:21.618254305Z"
  }
]

Delete a credential

DELETE /v1/model-gateway/provider-credentials/{credential_id} deletes the credential and its stored key; spend grants that name it can no longer be used. Returns 204 No Content, or 404 if there is no such credential.

Spend grants

Spend grants are Granite grants, created and revoked in Granite; Model Gateway has no endpoints for them. See Concepts.

Usage

GET /v1/model-gateway/spend-usage returns the person’s usage records, oldest first. Each has:

FieldMeaning
idThe record’s id
owner_uidThe person
grant_idThe Granite spend grant the call was counted against
authorization_idModel Gateway’s id for the call’s approval against the grant
resourcemodel:{provider}:{model}
unitsUnits counted. A model call Model Gateway makes counts one.
created_atWhen it was recorded

A person with no usage gets [].

Custom adapters

Create an adapter

POST /v1/model-gateway/custom-adapters

curl https://gqbzygqa4dd3t54xnb2fg5wcou0pitmm.lambda-url.us-east-1.on.aws/v1/model-gateway/custom-adapters \
  "${AUTH[@]}" -H "Content-Type: application/json" \
  -d '{
    "name": "my-llm",
    "dialect": "openai_chat",
    "base_url": "https://8.8.8.8/v1",
    "auth_style": "bearer",
    "models": ["my-model-1"]
  }'
FieldRequiredRules
nameYes1–128 characters: ASCII letters, digits, -, _, .. Unique for the person; not a built-in provider name.
dialectYesopenai_chat, anthropic or gemini
base_urlYeshttps://, resolving only to public addresses. A trailing / is removed.
auth_styleYesbearer, x_api_key or goog_key: the header that carries the key
modelsNoA list of model names. Stored and returned; not checked against calls.

Response, 201 Created:

{
  "auth_style": "bearer",
  "base_url": "https://8.8.8.8/v1",
  "created_at": "2026-11-05T20:41:21.880385766Z",
  "dialect": "openai_chat",
  "models": [
    "my-model-1"
  ],
  "name": "my-llm",
  "owner_uid": "gr_sub_alice",
  "updated_at": "2026-11-05T20:41:21.880385766Z"
}

Refusals look like this:

{"error": "adapter name cannot shadow a built-in preset"}
{"error": "base_url must use https"}
{"error": "base_url resolves to a disallowed (private, loopback, link-local, or metadata) address"}

A second adapter with the same name is 409.

List adapters

GET /v1/model-gateway/custom-adapters returns the person’s adapters without auth_style:

[
  {
    "base_url": "https://8.8.8.8/v1",
    "created_at": "2026-11-05T20:41:21.880385766Z",
    "dialect": "openai_chat",
    "models": [
      "my-model-1"
    ],
    "name": "my-llm",
    "owner_uid": "gr_sub_alice",
    "updated_at": "2026-11-05T20:41:21.880385766Z"
  }
]

Delete an adapter

DELETE /v1/model-gateway/custom-adapters/{name} returns 204 No Content, or 404 (custom adapter not found).

Public endpoints

curl -fsS https://gqbzygqa4dd3t54xnb2fg5wcou0pitmm.lambda-url.us-east-1.on.aws/health