> ## Documentation Index
> Fetch the complete documentation index at: https://docs.weaveos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom endpoints and gateways

> Route your own provider keys through an enterprise gateway such as Snowflake Cortex, Microsoft Foundry, Azure OpenAI, or a private deployment, rename models per endpoint, and authenticate with a key pair, Microsoft Entra service principal, or workload identity instead of a token

Some organizations don't call model vendors directly: inference runs through an enterprise gateway — Snowflake Cortex, a cloud marketplace endpoint, a private-cloud deployment, or an internal proxy — that speaks a vendor API but under its own hostname, its own model names, and its own credential type. Weave Router treats that gateway as a provider you bring a key for. This page covers the three things such a gateway usually needs.

Everything here is configured per provider key under **Billing & spend → Your provider keys**; see [bring your own provider keys](/router/billing#bring-your-own-provider-keys) for how BYOK keys are billed and stored.

## Choosing the endpoint's API

A gateway is added as one of two providers, depending on which API it exposes:

| Provider | Path it calls | Models it can serve |
| - | - | - |
| **Anthropic-compatible endpoint** | `/v1/messages` | Claude models, with thinking blocks and prompt caching |
| **OpenAI-compatible endpoint** | `/chat/completions` | Anything the endpoint publishes on the Chat Completions API |

Both require a base URL — they have no vendor default to fall back on. Give the base only, the way your provider client would: the router appends the API path itself.

<Note>
  You can add both for the same gateway, each with its own credential, when it
  exposes both APIs. Per model, the router prefers the Anthropic surface for
  Claude — it carries thinking blocks and `cache_control` natively — and uses
  the OpenAI-compatible one for everything else.
</Note>

### Example: Snowflake Cortex

Cortex publishes both APIs under one base URL, so a Snowflake org typically adds two keys pointing at the same place:

```
https://<account-identifier>.snowflakecomputing.com/api/v2/cortex/v1
```

The Anthropic-compatible key serves Claude; the OpenAI-compatible key serves the rest of the Cortex catalog (OpenAI, Llama, Mistral, DeepSeek, Snowflake's own models). The Snowflake user behind the credential needs the `SNOWFLAKE.CORTEX_USER` database role.

## Renaming models per endpoint

Gateways rarely publish models under the vendor's exact name — Cortex serves GPT-5 as `openai-gpt-5`, and an internal proxy might prefix everything. Add a **model alias** per key: the left side is the Weave catalog model, the right side is the name to put on the wire for that endpoint.

Only the outbound model name changes. Routing, pricing, reporting, and the model id your client sees back all stay on the catalog model, so an aliased gateway shows up in [reporting](/router/reporting) next to everything else. A key with no aliases sends catalog names unchanged.

Edit aliases from the **Aliases** column of the provider keys table. Editing them never asks for the credential again, so adding models to a gateway doesn't mean re-uploading the key.

For bearer-token gateway keys, Weave can **fetch the model list from your endpoint** once you enter the base URL and credential — the alias editor suggests IDs published by the gateway and warns when an alias does not appear on the endpoint. Use **Fetch models from endpoint** to refresh the list after the gateway adds models. Keys that authenticate with an RSA key pair or workload identity still use manual alias entry.

## Endpoint change history

Each time you save a new base URL for a provider key, Weave records a new version (the old row is retained, not overwritten in place). Click the **Endpoint** cell for a saved key to open its history: every URL that key pointed at, who saved it, and the window it was live. Alias-only edits do not create a new version — only endpoint URL changes appear in the history.

## Key-pair authentication

Most keys are a token the router sends as-is. Gateways whose tenant policy forbids long-lived tokens — Snowflake being the common case, where personal access tokens may be disallowed outright — can instead be given an **RSA private key**. The router then signs a short-lived JWT for the user you name and refreshes it well before the one-hour ceiling such gateways impose, so nothing has to be rotated by hand.

To use it, supply:

* the **private key**, an unencrypted PKCS#1 or PKCS#8 RSA key of at least 2048 bits (passphrase-protected keys are not supported)
* the **account identifier** — for Snowflake, the org-qualified name such as `MYORG-MYACCOUNT`
* the **user** the token is issued for, whose default role carries the gateway's inference privilege

The public half of the key must already be registered on that user before requests will be accepted — on Snowflake, `ALTER USER <user> SET RSA_PUBLIC_KEY='...'`.

<Note>
  The private key is encrypted at rest with the same protection as any other
  provider key, is never shown again after you save it, and is never sent
  upstream — only the JWTs signed from it are. Rotating it takes effect on the
  next request.
</Note>

Set it up under **Billing & spend → Your provider keys**: pick **RSA key pair**
for **Authentication**, paste the private key, and name the account and user.
On [self-hosted router](https://github.com/weave-os/router) deployments the
same fields are under **Settings → Provider API keys** and in the admin API.

<Note>
  Key pairs apply to gateway endpoints only. Keys for a vendor's own API —
  OpenAI, Anthropic, Google — authenticate with the token that vendor issues.
</Note>

## Workload identity

A gateway that supports workload identity federation can skip the credential entirely. Instead of storing a secret, the router proves *its own* cloud identity on every request — a Google-signed ID token for the service account it runs as, or a projected OIDC token in its pod — and the gateway's tenant grants that identity access. Nothing is stored, so nothing has to be rotated or can leak.

Pick **Workload identity (no credential stored)** for **Authentication**; there is no key, account, or user to enter. Like key pairs, it applies to gateway endpoints only.

On Snowflake, the setup is on their side: a `WORKLOAD_IDENTITY` security integration trusting the router's identity, bound to a service user created with no password or key and granted `SNOWFLAKE.CORTEX_USER`. See Snowflake's [workload identity federation](https://docs.snowflake.com/en/user-guide/workload-identity-federation) guide.

```sql theme={null}
CREATE ROLE weave_cortex_role;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE weave_cortex_role;

CREATE USER weave_router
  TYPE = SERVICE
  WORKLOAD_IDENTITY = (
    TYPE = GCP,
    SUBJECT = '112122049841801808867'
  )
  DEFAULT_ROLE = weave_cortex_role;

GRANT ROLE weave_cortex_role TO USER weave_router;
```

`SUBJECT` is the numeric unique ID of the identity the router attests as. For a
Weave-managed router that is `router-user@workweave-prod-01.iam.gserviceaccount.com`,
unique ID `112122049841801808867`. Self-hosted on GCP, use your own service account's
unique ID (`gcloud iam service-accounts describe <email> --format='value(uniqueId)'`);
on Kubernetes, use `TYPE = OIDC` with your cluster's issuer and the projected token's
subject instead.

Point both provider keys at the Cortex REST base URL —
`https://<account-identifier>.snowflakecomputing.com/api/v2/cortex/v1` — one as an
OpenAI-compatible endpoint, one as an Anthropic-compatible endpoint.

<Note>
  Weave-managed routers attest as a Google service account, so the gateway sees
  one Weave identity rather than a per-organization principal — upstream spend
  attribution is per deployment. A [self-hosted
  router](https://github.com/weave-os/router) attests as your own workload
  (GCP service account or projected OIDC token), which keeps the identity yours.
</Note>

## Microsoft Entra ID

Microsoft Foundry and Azure OpenAI v1 gateway endpoints can authenticate with a
Microsoft Entra service principal instead of a long-lived inference token. The
router stores the client secret encrypted, exchanges it for a short-lived bearer
token, refreshes it before expiry, and never sends the client secret to the
inference endpoint.

Pick **Microsoft Entra ID (service principal)** for **Authentication** under
**Billing & spend → Your provider keys**. Enter:

* **Tenant ID** — the Entra directory/tenant ID
* **Client ID** — the application/service-principal ID
* **Client secret** — the secret generated for that application

Use `anthropic_gateway` for Foundry Claude and `openai_gateway` for Azure
OpenAI v1. Both require their Azure resource base URL. Add a model alias for
every model you want this gateway to serve, mapping the catalog model ID to the
Azure deployment name, for example `claude-opus-5` → `my-claude-deployment`.

<Note>
  The router runs on GCP Cloud Run, so Azure managed identity is not available
  to it. The application needs permission to call the Azure resource, such as
  Foundry User for Foundry Claude or Cognitive Services OpenAI User for Azure
  OpenAI. The older Azure OpenAI `/openai/deployments/...` route with an
  `api-version` query parameter is not supported by this configuration; use the
  v1 endpoint shape.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.