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

# Models and provider keys

> Choose who pays for a model: Orca credit, or your own provider key.

Every agent needs a model, and its `model` field says where the model runs and who pays:

| | Orca credit | Your own provider key |
| - | - | - |
| **`model` looks like** | `orca/openrouter/<OpenRouter id>`, such as `orca/openrouter/anthropic/claude-sonnet-4.5` | `<provider>/<id>`, such as `anthropic/claude-sonnet-4-5` or `openrouter/anthropic/claude-sonnet-4.5` |
| **Runs on** | OpenRouter, with Orca's key | That provider, with your key |
| **Who pays** | Your Orca credit: OpenRouter's price plus OpenRouter's 5.5% credit fee, passed on at cost | You, at that provider |
| **Setup** | None | Store your provider key in Orca once |
| **Find model names** | `client.models.list()` | That provider's catalog |

A model name always says who pays. A name with no provider part (`gpt-5`) is refused, and Orca never translates a name from one catalog into another's: `anthropic/claude-sonnet-4.5` is OpenRouter's name for that model, not Anthropic's, so it does not run on your Anthropic key.

Provider keys are separate from your Orca API key and from [tool credentials in vaults](/guides/credentials).

## Discover Orca credit models

With the client configured as in the [quickstart](/quickstart):

```python theme={"dark"}
for model in client.models.list().data:
    print(model.id)  # orca/openrouter/<OpenRouter id>
```

`GET /v1/models` lists OpenRouter's catalog as Orca credit models. A listed model is not a promise that every agent setting or tool works with it.

`GET /api/models` (an Orca extension, outside `/v1`) lists every model you can pick, grouped by who pays: an Orca credit group with OpenRouter's input and output price per million tokens, then one group per provider you have a key for, billed by that provider. It also returns the OpenRouter credit fee in effect:

```json theme={"dark"}
{
  "object": "list",
  "openrouter_fee_bps": 550,
  "groups": [
    {"payer": "orca_credit", "provider": "openrouter", "label": "Orca credit", "available": true,
     "models": [{"id": "orca/openrouter/openai/gpt-5.6-luna", "name": "OpenAI: GPT-5.6 Luna",
                 "context_length": 400000,
                 "input_micro_usd_per_million": 200000, "output_micro_usd_per_million": 1200000}]},
    {"payer": "own_key", "provider": "openai", "label": "OpenAI", "available": true,
     "models": [{"id": "openai/gpt-5.6-luna"}]}
  ]
}
```

Prices are in micro-USD (millionths of a dollar) per million tokens, as OpenRouter publishes them, and `null` where OpenRouter has no fixed price. They are shown for choosing a model; the charge is always what OpenRouter reports for the call. Orca reads each list at most every 10 minutes and keeps the last good copy; a group whose list cannot be read has `available: false` and no models.

## What Orca credit costs

Each call on Orca credit is charged what OpenRouter reports it cost, including its cache and reasoning tokens, plus OpenRouter's credit fee (5.5% today). Orca adds no markup and keeps no price list: the price is OpenRouter's at the time of the call. Your usage shows each call's cost, the provider's cost and the fee.

`web_search` runs on your agent's own model, through the same route and key as its calls, and whoever pays for that model pays for the search. On an Orca credit model the search is charged like a call: what OpenRouter reports for it, plus the fee. On your own OpenRouter, OpenAI or Anthropic key it uses that provider's web search on your key, the provider bills it, and Orca charges nothing. A search never falls back to Orca credit or to another model. The answer and its cited links come back to your agent's model.

## Connect a provider

Provider management is an **Orca extension** under `/api/providers`, outside the OpenAI `/v1` surface. Use ordinary authenticated HTTP requests, not `client.beta.agents` methods, at `https://api.orcapods.ai` without `/v1`. Setting and removing a key needs the [admin role](/organizations#roles); in the dashboard it is **BYOK** under **Settings**, a page titled Providers.

```bash theme={"dark"}
export ORCA_ORIGIN="https://api.orcapods.ai"
# See which providers are supported and which you have keys for
curl --fail-with-body "$ORCA_ORIGIN/api/providers" -H "Authorization: Bearer $ORCA_API_KEY"

# Store your Anthropic key (read from an environment variable, not typed inline)
curl --fail-with-body -X PUT "$ORCA_ORIGIN/api/providers/anthropic/key" \
  -H "Authorization: Bearer $ORCA_API_KEY" -H "Content-Type: application/json" \
  -d "{\"api_key\": \"$ANTHROPIC_API_KEY\"}"

# List the models that key can use
curl --fail-with-body "$ORCA_ORIGIN/api/providers/anthropic/models" -H "Authorization: Bearer $ORCA_API_KEY"
```

The response includes provider IDs, whether you have a key, whether a catalog is public, and `unsupported_agent_fields`. It never returns the stored key.

| Method | Path | Purpose |
| - | - | - |
| GET | `/api/providers` | List supported providers and key status |
| GET | `/api/providers/{provider}` | Retrieve provider status |
| PUT | `/api/providers/{provider}/key` | Set or replace a key with `{"api_key":"…"}` |
| DELETE | `/api/providers/{provider}/key` | Remove your key |
| GET | `/api/providers/{provider}/models` | Read that provider's catalog |
| GET | `/api/models` | Every model you can pick, grouped by who pays, with Orca credit prices |
| GET | `/api/sessions/{session_id}/model` | The model a session's next turn uses, and who pays |
| POST | `/api/sessions/{session_id}/model` | Switch one session's model with `{"model":"…"}` |

Supported IDs are `openai`, `anthropic`, `openrouter`, `vercel`, and `cheaperinference`. Catalogs marked `public_catalog` can be read without a provider key; other catalogs require one. Provider catalog requests still require Orca authentication.

Submit keys from trusted backend code or your secret-management workflow. Do not paste a real provider key into documentation examples, browser code, command history, or logs. The service validates a new key before accepting it; an invalid key returns HTTP 400.

## Select the model explicitly

Use `orca/openrouter/<OpenRouter id>` for Orca credit, or `<provider>/<id>` for your own key. An OpenRouter id already contains a namespace, so it becomes `orca/openrouter/<vendor>/<model-name>` or `openrouter/<vendor>/<model-name>`. Get the actual id from the catalog rather than copying a stale example.

```python theme={"dark"}
agent = client.beta.agents.create(
    model="orca/openrouter/YOUR_OPENROUTER_MODEL_ID",
    instructions="Be concise and state uncertainty.",
)
```

Every save checks the model: creating or updating an agent (HTTP 400 on `model`), creating a session with an inline agent (on `agent.model`), and publishing or copying a kit. A save is refused when:

* the name has no provider part, or uses `orca/` with any provider but OpenRouter;
* it names your own key for a provider where you have none: "Add your Anthropic key in Settings, Providers, or choose an Orca credit model". When OpenRouter offers the same name, the message gives its Orca credit name instead: "Add your Anthropic key in Settings, Providers, or use orca/openrouter/anthropic/claude-sonnet-4.5 for Orca credit";
* the provider does not list the model: "Anthropic does not offer the model …";
* with your key saved, it is OpenRouter's name for a model the provider lists under another id, such as `anthropic/claude-sonnet-4.5`: the message names `orca/openrouter/anthropic/claude-sonnet-4.5` for Orca credit, `openrouter/anthropic/claude-sonnet-4.5` with your OpenRouter key, or the provider's own id with its key.

When a provider's list cannot be read, the agent is saved unchecked and the response carries an `Orca-Warning` header saying so. Nothing else changes in the response.

A turn checks your key again when it starts. Nothing ever falls back from your key to Orca credit, or from Orca credit to your key.

## Check capability limits

* Inspect `unsupported_agent_fields` before sending provider-specific settings.
* Anthropic does not accept JSON-schema `text.format`, non-default `text.verbosity`, or non-`auto` `service_tier` in this integration.
* On your own OpenAI key, some reasoning models refuse tools at their default reasoning effort: OpenAI refuses `gpt-5.6-luna` with any tool unless `reasoning.effort` is `none`, and the turn fails with "the provider rejected the request (HTTP 400)". Set `reasoning.effort: none` on such agents. Orca never sets it for you.
* `web_search` accepts `allowed_domains`, `location`, `context_size` and `mode` `live` or `disabled`; `mode: cached` is not available. On an Anthropic model, `context_size` must stay `medium`, the default.
* Vercel AI Gateway and CheaperInference keys have no web search. Saving an agent with `web_search` on their models is refused with HTTP 400 on `agent.tools`; use `mode: disabled`, or a model on Orca credit or on an OpenRouter, OpenAI or Anthropic key.
* If a provider refuses a search for its model, the tool returns an error naming the model, and the turn goes on.
* `reasoning.summary` is not available on any route; reasoning summaries are not exposed. Saved agents that set it are rejected on create or update.
* A catalog entry is not a promise of tool support or availability on your provider account.

## Rotate and remove keys carefully

Who pays is fixed when a turn starts: Orca reads your keys then, and every call of that turn, its subagents' included, runs on them. Saving, replacing or removing a key applies from the next turn.

Removing a key makes the next turn of sessions using it fail with HTTP 400 on `agent.model`; it never moves them to Orca credit. Restore a valid key before continuing affected sessions.

When credit runs out on either side, the turn ends with `usage_limit_exceeded` and a `param` that says whose: `orca_credit` for your Orca credit, `provider_quota` for your own key's provider account. See [errors](/reference/errors#turn-errors).

## Switch who pays for one session

Orca never switches on its own. When one side runs out, top it up, or switch that session to a model on the other side:

```bash theme={"dark"}
curl --fail-with-body -X POST "$ORCA_ORIGIN/api/sessions/$SESSION_ID/model" \
  -H "Authorization: Bearer $ORCA_API_KEY" -H "Content-Type: application/json" \
  -d '{"model": "openrouter/openai/gpt-5.6-luna"}'
```

```json theme={"dark"}
{"object": "session.model", "session_id": "session_…", "model": "openrouter/openai/gpt-5.6-luna",
 "agent_model": "orca/openrouter/openai/gpt-5.6-luna", "payer": "own_key"}
```

* The model is checked as a save is, and must run the agent's settings on its provider.
* It applies from the session's next turn. While a turn runs, including one waiting for your function results, the switch is refused with HTTP 409.
* It is for that session only. The agent, the session's `/v1` object and the agent's other sessions keep the agent's model. `GET /api/sessions/{session_id}/model` shows the model the next turn uses, the agent's own, and `payer` (`orca_credit` or `own_key`).
* Switching back to the agent's own model removes the switch.

Switching may re-send this conversation without the provider's cache, which uses more tokens. The model may behave differently through another route, and work in progress may not carry over correctly. The same model exists on both sides only under OpenRouter's id: `openrouter/<id>` and `orca/openrouter/<id>`.


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