# Bring your own keys

Any provider this deployment serves takes a key of your own. Send one with a call, or save keys for your organization and choose, key by key, whether each is tried before Momor’s keys or after them.

## Which key a call runs on

A call is tried on keys in this order. It moves on only when a key fails, or does not apply to the call:

| Order | Key | Notes |
| --- | --- | --- |
| `1` | A key the request carries | Sent with the call in keys, on POST /models. |
| `2` | Your prioritized keys | In their order. A key whose filters do not match the call is passed over. |
| `3` | Momor’s keys | Only for a provider Momor resells, whose catalog rows say resale: true, and only where no prioritized key’s rule keeps them out. |
| `4` | Your fallback keys | In their order, after Momor’s keys. |

A provider order in the request, [`prioritization.order`](/docs/gateway/choosing-a-model/#choosing-providers), or your organization’s [default order](/docs/gateway/choosing-a-model/#organization-defaults) for a call that sends none, decides which provider goes first. Within each provider, your organization’s key goes before Momor’s.

An offering no key applies to is passed over. The [call record](/docs/gateway/reference/generation/) says whether the call, and each attempt, ran on your own key in `ownKey`.

## Prioritized and fallback keys

Your organization can save several keys for one provider, or for one of its regions. Saved keys sit in two lists, and within each list they are tried in the order you put them in.

| List | Its keys are tried |
| --- | --- |
| Prioritized | Before Momor’s keys. |
| Fallback | Only after Momor’s keys. |

In the API the list is a key’s `section`, `Prioritized` or `Fallback`, and its place in that list is `position`, counted from 0.

Saved keys are used in your Gateway organization’s own calls. A Workflow organization saves its own provider keys, in its own Settings, for the model calls its workflows make.

## Using Momor’s keys

Each prioritized key has one rule for Momor’s keys, with three choices:

| Choice | What it does |
| --- | --- |
| If this key fails, use Momor’s · Default | Momor’s keys are tried after your prioritized keys and before your fallback keys. |
| Never for the models this key covers | Momor’s keys serve none of the models this key covers. A call to one of them goes from your prioritized keys to your fallback keys. |
| Never for anything on this provider | Momor’s keys serve no call on this provider, whatever the model. |

In the API the rule is `momorFallback`: `Allowed`, `NeverForKeyModels` or `NeverForProvider`, in the order above. A fallback key’s rule has no effect.

## Filters

Each saved key has three optional filters. An empty filter means all, and a key is used only when every filter it sets matches the call.

| Filter | What it limits |
| --- | --- |
| Models · models | The models the key may serve, by id, publisher/name. |
| API keys · apiKeys | Which of your organization’s API keys may use it, by id. |
| Members · members | Which of your organization’s members may use it, by id. A call made with an API key counts as made by the member who created that key. |

## Zero data retention

Mark a saved key `zdr` when your organization’s own zero-data-retention agreement with the provider covers it. Each [saved key](#list-saved-keys) carries `zdr`, and [saving](#save-a-key) and [changing](#change-a-key) a key set it; it is `false` unless you set it.

A call runs under zero data retention when it asks to, with `prioritization.zdr` on [`POST /models`](/docs/gateway/reference/chat/) and its typed routes or `provider.zdr` on [Chat Completions](/docs/gateway/reference/chat-completions/), or when your organization holds every call to it. The organization’s owner, signed in, turns that on:

```http
PATCH /organization/preferences
{ "modelRouting": { "prioritization": { "zdr": true } } }
```

With it on, every Gateway call the organization makes runs under zero data retention, whatever the call sends: a call’s own `false` does not turn it off. See [organization defaults](/docs/gateway/choosing-a-model/#organization-defaults).

Under zero data retention, a call runs only on your saved keys marked `zdr` and on Momor’s keys that Momor’s own agreements with the provider cover. A key sent with the call in `keys` is not used, and `fileProcessing` other than `none` is refused with `400`. A model that nothing covered can run is refused with `404`: `No configured model answering to <name> runs on a key the caller or Momor holds.`

The [call record](/docs/gateway/reference/generation/) keeps the call’s `prioritization`, `zdr` included.

## What a call on your key costs

The provider bills a call that runs on your key to your account, whether the key was sent with the call or saved. Momor charges a share of the call’s list price from your organization’s credits: 5% by default, a setting of the deployment. The same share applies to Search and to workflow runs on your saved keys. A call listed at $1.00 is $1.00 on your provider’s invoice and $0.05 from your credits; the same call on Momor’s keys is $1.00 from your credits. See [credits and pricing](/docs/gateway/credits/).

## Send a key with a call

On [`POST /models`](/docs/gateway/reference/chat/), send it in `keys`, by the provider's name, matched without regard to case:

```json
"keys": { "togetherai": "tgp_v1_…" }
```

Some providers need values besides the key. Such a key is sent as an object holding `key` and those values:

```json
"keys": { "azure": { "key": "…", "resourceName": "acme-ai" } }
```

A key missing a value its provider needs, or carrying one it does not take, is refused with `400`, and so is a key for a provider this deployment does not serve. Keys are never written to the call record or the logs. [Chat Completions](/docs/gateway/reference/chat-completions/) has no `keys`: it runs on saved keys and Momor's.

## Save keys for your organization

The organization's owner, signed in, saves and manages keys, each addressed by its `id`. A key is tried against one of its provider's models before it is saved, and a key the provider refuses is not saved. A provider with no model a key can be tried against cannot have a key saved; its key still works per call, sent in `keys`.

A key is saved for a provider's root or for one of its regions. A key saved for the root runs the root and all its regions; a key saved for a region runs that region alone.

## List the providers

`GET https://api.momor.ai/organization/byokeys/providers`

Every provider whose key can be saved, a page at a time, as `{ "count", "items": [{ "provider", "fields", "regions", "fee" }] }`: `count` is how many there are, `skip` passes over that many providers (0 by default) and `take` sets how many a page holds, from 1 to 200 (50 by default). `fields` names the values its key must come with, such as `resourceName` for `azure`. `regions` names the regions a key can be saved for alone, such as `["eu"]`. `fee` is the share of a call's list price Momor charges where the call runs on such a key, such as `0.05`.

## List saved keys

`GET https://api.momor.ai/organization/byokeys`

A page of the saved keys, as `{ "count", "items" }`: `count` is how many keys are saved, and `items` the page, the prioritized keys first, then the fallback keys, each list in its order. `skip` passes over that many keys (0 by default) and `take` sets how many a page holds, from 1 to 200 (50 by default). Each key:

- `id` (string): The key's id, which the routes below take.
- `providerId` (string): The id of the provider, or of the region, the key is saved for.
- `provider` (string): The provider's name.
- `region` (string): The region the key is saved for alone, or null for a key saved for the root.
- `label` (string): Your name for the key.
- `hint` (string): The key's last four characters. The key itself is not listed.
- `fields` (object): The values the key comes with, by name.
- `status` (string): Whether the provider took the key when it was last tried. Values: `Working`, `Rejected`.
- `lastUsedAt` (date-time): When the key was last used.
- `section` (string): The list the key is in. Values: `Prioritized`, `Fallback`.
- `position` (integer): Its place in that list, counted from 0.
- `momorFallback` (string): Its rule for Momor's keys. It matters only on a prioritized key. Values: `Allowed`, `NeverForKeyModels`, `NeverForProvider`.
- `models` (string[]): The models it may serve, by id, publisher/name. Empty means all.
- `apiKeys` (string[]): The ids of the API keys that may use it. Empty means all.
- `members` (string[]): The ids of the members who may use it. Empty means all.
- `zdr` (boolean): Whether your organization's own zero-data-retention agreement with the provider covers the key.

```json
{
  "count": 1,
  "items": [
    {
      "id": "0b6a5f8e-2c41-4d9b-9f0e-7a3c1d2e4f50",
      "providerId": "5d2e9c71-8a3f-4b6e-a1c0-3f7b9e2d1a64",
      "provider": "azure",
      "region": null,
      "label": "Production",
      "hint": "a91f",
      "fields": { "resourceName": "acme-ai" },
      "status": "Working",
      "lastUsedAt": "2026-10-22T09:14:03Z",
      "section": "Prioritized",
      "position": 0,
      "momorFallback": "Allowed",
      "models": [],
      "apiKeys": [],
      "members": [],
      "zdr": true
    }
  ]
}
```

## Save a key

`POST https://api.momor.ai/organization/byokeys`

- `provider` (string, required): The provider's name, as the providers list gives it.
- `region` (string): A region the providers list gives in regions, such as eu, to save the key for that region alone. Left out, the key is saved for the root and runs the root and all its regions.
- `key` (string, required): The key.
- `label` (string): Your name for the key.
- `fields` (object, default `{}`): The values the provider's key must come with, each under a name the providers list gives in fields.
  - `resourceName` (string): For azure: the name of your Foundry resource.
- `section` (string): The list the key goes in. Values: `Prioritized`, `Fallback`.
- `position` (integer, default `last`): Its place in that list, counted from 0. Left out, the key goes last in its list.
- `momorFallback` (string, default `Allowed`): Its rule for Momor's keys, as in Using Momor's keys above. It matters only on a prioritized key. Values: `Allowed`, `NeverForKeyModels`, `NeverForProvider`.
- `models` (string[], default `[]`): The models the key may serve, by id, publisher/name. Empty means all.
- `apiKeys` (string[], default `[]`): The ids of the API keys that may use it, as GET /organization/apikeys lists them. Empty means all.
- `members` (string[], default `[]`): The ids of the members who may use it. Empty means all. A call made with an API key counts as made by the member who created that key.
- `zdr` (boolean, default `false`): Whether your organization's own zero-data-retention agreement with the provider covers the key. See Zero data retention above.

The provider is tried with the key first. The answer is `201` with the saved key, in the shape the listing gives.

```http
POST /organization/byokeys
{ "provider": "azure", "key": "…", "label": "Production", "fields": { "resourceName": "acme-ai" }, "section": "Prioritized", "momorFallback": "NeverForKeyModels", "zdr": true }
```

## Change a key

`PATCH https://api.momor.ai/organization/byokeys/{id}`

The body is the key's whole settings form: every field `POST` takes except `provider` and `key`, so send each setting as the key should have it. Changed `fields` are tried with the provider on the saved key before anything is saved. The answer is `200` with the saved key.

- `id` (string, required): In the path: the key's id.
- `label` (string): Your name for the key.
- `fields` (object): The values the provider's key must come with.
- `section` (string): The list the key is in. Values: `Prioritized`, `Fallback`.
- `position` (integer): Its place in that list, counted from 0.
- `momorFallback` (string): Its rule for Momor's keys. Values: `Allowed`, `NeverForKeyModels`, `NeverForProvider`.
- `models` (string[]): The models the key may serve. Empty means all.
- `apiKeys` (string[]): The ids of the API keys that may use it. Empty means all.
- `members` (string[]): The ids of the members who may use it. Empty means all.
- `zdr` (boolean, default `false`): Whether your organization's own zero-data-retention agreement with the provider covers the key.

To reorder, send the key with its new `position`: the rest of its list is renumbered around it. Changing `section` moves the key to the other list.

```http
PATCH /organization/byokeys/0b6a5f8e-2c41-4d9b-9f0e-7a3c1d2e4f50
{ "label": "Production", "fields": { "resourceName": "acme-ai" }, "section": "Prioritized", "position": 1, "momorFallback": "Allowed", "models": [], "apiKeys": [], "members": [], "zdr": true }
```

## Replace a key

`PUT https://api.momor.ai/organization/byokeys/{id}`

Replaces the saved key with a new one: the body is the settings form `PATCH` takes, with the new `key`. The new key is tried with the provider before anything is saved. Adding, replacing and removing a key each need the owner to have confirmed it is them in the last five minutes, with the code `POST /authorization/code/send` emails them and `POST /authorization/code/verify` checks; without it the answer is `403`.

## Test a key

`POST https://api.momor.ai/organization/byokeys/{id}/test`

Tries the saved key with its provider again and records the result in its `status`. The answer is `200` when the provider takes it.

## Remove a key

`DELETE https://api.momor.ai/organization/byokeys/{id}`

Removes the saved key.

## Errors from these routes

A failure carries `{ "message" }`.

| Status | Code | What happened |
| --- | --- | --- |
| `400` | `—` | POST or PUT: a setting is wrong, and the message names it, such as models: x is not a model served by Anthropic., <id> is not one of the organization's API keys. or <id> is not a member of the organization. |
| `404` | `—` | PUT: no saved key has that id. |
| `429` | `—` | Test: the provider is rate-limiting the key. |
| `502` | `—` | POST, PUT with a new key or changed fields, or test: the provider refused the key, as <Provider> refused the caller's own key for it: … |
| `503` | `—` | Test: the provider was unavailable. |

Coming: the call record and the activity log naming which saved key served each attempt.

## Provider notes

A `vertex` key is the service-account key Google Cloud issues, its JSON sent as the string, and the call runs in the project the key names. `vertex` calls run on Google's `global` endpoint, which serves every Gemini model on Vertex; a `region` in the service-account key is not used yet.

An `azure` key is a key of your Foundry resource and `resourceName` is that resource's name. Calls run at `https://{resourceName}.openai.azure.com/openai/v1/`, naming the model by Azure's id for it, so each model you call needs a deployment under that id in your resource.

## When your key fails

A provider refusing your key answers `502` and a provider rate-limiting it answers `429`, each naming the provider, so your key's failure is told apart from Momor's:

| Message | Status |
| --- | --- |
| `<provider> refused the caller's own key for it: …` | `502` |
| `<provider> is rate-limiting the caller's own key: …` | `429` |

A saved key a provider refuses is marked `Rejected` in the listing.
