# Third-party APIs — `/ext/{route}/...`

An admin can register any HTTP API as a **route**. Callers reach it at
`/ext/{route}/<upstream path>` with an ordinary gateway key; the gateway
injects the upstream's credential (and signs the request, where the API
requires it), forwards method, path, query, headers and body **verbatim**,
and returns the upstream's response verbatim plus `X-Gateway-*` headers.

    curl "https://gw.mizint.com/ext/weather/v1/now?city=Bangkok" -H "Authorization: Bearer $GW_KEY"

Rules:

- Routes are **deny-by-default**: your key must be granted each route
  (`403 route_not_permitted` otherwise). `/v1/models` does not list
  routes; ask the admin, or read `tools/list` on `/mcp`, where routes
  published as tools appear.
- The upstream credential never reaches you. Your own `Authorization`
  header is stripped before forwarding.
- Upstream errors are **not** translated: a 4xx/5xx and its body come
  back exactly as the upstream sent them. The gateway acts on exactly
  one class of failure — the upstream's declared *authentication*
  failures, which it remedies once (token refresh) or flags for the
  admin.

## Resource-scoped routes

Some APIs are per-tenant (a shop, an account). Such routes need

    X-Gateway-Resource: <resource key>

on every call, and your key must be granted that resource
(`403 resource_not_permitted`; missing header → `400 resource_required`).

    GET /gw/resources
    -> {"data":[{"key":"acme-shopee","route":"shopee","external_id":"12345","status":"active","expires_at":"..."}]}

lists the resources your key may use — never any credential. A resource
whose grant died is `status: needs_reauth` and calls on it are
`503 resource_needs_reauth` until an admin re-authorises it; a route
whose app secret died is likewise 503 until the admin installs a new
one.

## Attribution and cost

`X-Gateway-Context: {"run":"r1"}` (a JSON object) on the request is
recorded on the spend log verbatim, the way `gw_context` is for AI
calls — the body cannot carry it because the body is forwarded as-is.

Each route carries a flat price per call, charged on every request or
only on requests matching the route's `charge_on` rule — so polling a
queue API costs nothing while the submit does. `X-Gateway-Cost-Usd` on
the response says what this call cost.
