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

> ## Agent Instructions
> Phaseo Gateway base URL: https://api.phaseo.app/v1. Send `Authorization: Bearer $PHASEO_API_KEY` with every request.
> Model IDs look like `provider/model`, for example `openai/gpt-6-astra`. Do not guess IDs: list them with `GET /v1/models` or check https://phaseo.app/models. `phaseo/free` routes to an available free model and needs no wallet balance.
> For new text integrations prefer `POST /v1/responses`. `POST /v1/chat/completions` (OpenAI format) and `POST /v1/messages` (Anthropic format) suit existing code.
> The full API contract is https://phaseo.app/docs/openapi/v1/openapi.yaml. Official SDKs: `@phaseo/sdk` (TypeScript) and `phaseo` (Python), plus Go, C#, PHP, Ruby and Rust.
> Search these docs over MCP at https://phaseo.app/docs/mcp, and install Phaseo skills with `npx skills add https://phaseo.app/docs`. If a page is wrong or out of date, report it with the MCP `submit_feedback` tool.
> Manage Phaseo accounts with the `phaseo` CLI (`npm install -g @phaseo/cli`, then `phaseo login` or `phaseo login --device-code`), the `/v1` Management API or the MCP server at `https://mcp.phaseo.app/mcp?access=manage`. Do not send users to the dashboard for account tasks. A person is still needed for sign-up, approving a sign-in, paying the first top-up on the checkout link that `phaseo credits add` returns when no card is saved, confirming each saved-card top-up from the emailed link, and account security (password, MFA, passkeys). Create API keys with `phaseo keys create --name <name> --json`; never guess one. Credit top-ups need `phaseo login --scopes billing:write` first. Task map: https://phaseo.app/docs/v1/developers/manage-from-an-agent.md.

# Migrate from OpenRouter to Phaseo

> Use Phaseo as an OpenRouter alternative by changing your gateway URL and API key, validating model IDs, and testing a controlled rollout.

Phaseo is an OpenAI-compatible alternative to OpenRouter. If your app already uses OpenRouter through the OpenAI SDK or direct HTTP calls, you can usually migrate at the client boundary without rewriting prompts or application logic.

## What changes

| Setting | OpenRouter | Phaseo |
| - | - | - |
| Base URL | `https://openrouter.ai/api/v1` | `https://api.phaseo.app/v1` |
| API key variable | `OPENROUTER_API_KEY` | `PHASEO_API_KEY` |
| Authentication | `Authorization: Bearer <key>` | `Authorization: Bearer <key>` |
| Request payload | OpenAI-compatible | Keep unchanged for the first migration pass |
| Model IDs | OpenRouter catalog | Verify each ID with `GET /v1/models` |

The migration has four parts:

1. Keep payload shape unchanged.
2. Swap base URL and API key source.
3. Verify model IDs and any OpenRouter-only headers.
4. Roll traffic gradually while comparing latency, output, and cost behavior.

## Before you start

* Access to the current OpenRouter integration code and deployment config.
* `PHASEO_API_KEY` available in dev, staging, and production.
* A short list of production model IDs and representative prompts.

## 1) Inventory current OpenRouter usage

Start by identifying every place OpenRouter is referenced: endpoint URLs, keys, model IDs, and any provider-specific headers.

* Find `openrouter.ai` endpoint references.
* Find `OPENROUTER_API_KEY` usage in code, CI, and hosting env vars.
* Find OpenRouter-only headers such as `HTTP-Referer` and `X-Title`.
* Document active model IDs and any fallback-chain logic.
* Document any reusable prompt, provider, or parameter defaults that should move into Gateway presets instead of staying duplicated in application code.

## 2) Swap base URL and credentials

Keep request payload shape unchanged first. Do behavior parity before optimization.

```typescript TypeScript theme={null}
// Before
import OpenAI from "openai";

const before = new OpenAI({
  apiKey: process.env.OPENROUTER_API_KEY,
  baseURL: "https://openrouter.ai/api/v1",
});

const response = await before.chat.completions.create({
  model: "openai/gpt-4.1-mini",
  messages: [{ role: "user", content: "Summarize our migration plan." }],
});
```

```typescript TypeScript theme={null}
// After
import OpenAI from "openai";

const after = new OpenAI({
  apiKey: process.env.PHASEO_API_KEY,
  baseURL: "https://api.phaseo.app/v1",
});

const response = await after.chat.completions.create({
  model: "openai/gpt-4.1-mini",
  messages: [{ role: "user", content: "Summarize our migration plan." }],
});
```

```bash cURL theme={null}
# Before
curl -s "https://openrouter.ai/api/v1/chat/completions" \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4.1-mini",
    "messages": [{"role":"user","content":"Say hello"}]
  }'

# After
curl -s "https://api.phaseo.app/v1/chat/completions" \
  -H "Authorization: Bearer $PHASEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4.1-mini",
    "messages": [{"role":"user","content":"Say hello"}]
  }'
```

## 3) Validate model IDs and map OpenRouter-only behavior

Do not assume every previous alias is valid. Query `/v1/models` and verify each production model ID. The default response contains only models that are publicly routable now; use `availability=all` only when you intentionally need to inspect inactive or coming-soon mappings.

```bash cURL theme={null}
curl -s "https://api.phaseo.app/v1/models" \
  -H "Authorization: Bearer $PHASEO_API_KEY" | jq '.data[0:10] | map(.id)'
```

* Keep `Authorization: Bearer` format unchanged.
* Keep `HTTP-Referer` and `X-Title` when they identify the calling application. Phaseo accepts the lowercase equivalents `http-referer` and `x-title`.
* If callers depend on OpenRouter-only response fields, adapt them in one compatibility layer instead of changing every caller.
* If your OpenRouter setup relies on provider allow/deny lists or routing defaults, map those into [Presets](https://phaseo.app/docs/v1/guides/presets.md) and [Routing and Fallbacks](https://phaseo.app/docs/v1/guides/routing-and-fallbacks.md) instead of scattering them across callers.

Do not copy OpenRouter provider preferences or response-only fields into every call site. Keep those differences in one adapter so rollback remains a base URL and credential change.

### Map provider controls

Several common provider controls have direct Phaseo equivalents:

| Existing field | Phaseo field | Notes |
| - | - | - |
| `provider.order` | `provider.order` | Try providers in a preferred sequence. |
| `provider.only` | `provider.only` | Restrict the request to an approved set. |
| `provider.ignore` | `provider.ignore` | Remove providers from consideration. |
| `provider.sort` | `provider.sort` | Supports `price`, `latency`, and `throughput`. |
| `provider.zdr` | `provider.require_zero_data_retention` | Require a zero-data-retention-capable route. |

Phaseo also supports `provider.required_execution_region` and `provider.required_data_region` when a workload needs regional controls. See [Pin or ignore providers](https://phaseo.app/docs/v1/cookbook/pin-or-ignore-providers-per-request.md) and [Route only to EU or ZDR-capable providers](https://phaseo.app/docs/v1/cookbook/route-only-to-eu-or-zdr-providers.md) for complete requests.

## 4) OpenRouter parity checklist

Use this checklist before shifting meaningful traffic:

* Base URL updated to `https://api.phaseo.app/v1`.
* `OPENROUTER_API_KEY` replaced with `PHASEO_API_KEY` in all environments.
* All production model IDs verified against `/v1/models`.
* One non-streaming request validated through `/v1/chat/completions` or `/v1/responses`.
* One streaming request validated through the same app-level integration path used in production.
* Generation lookups rechecked through `GET /v1/generations?id=<request_id>` so failed requests can be replayed from the stored `replay_request` payload when `replay_supported=true`.
* Tool-calling and structured-output flows rechecked with real prompts.
* Invalid-key and invalid-model failures verified in staging.
* Any OpenRouter-only headers or response fields either removed or explicitly normalized.
* Shared prompt/routing defaults moved into presets where appropriate.

### Agent migration checklist

Give a coding agent this bounded sequence:

1. Search runtime code and deployment config for `openrouter.ai`, `OPENROUTER_API_KEY`, `sk-or-v1`, `HTTP-Referer`, and `X-Title`.
2. Change the client boundary to `https://api.phaseo.app/v1` and `PHASEO_API_KEY` without adding a secret value to source control.
3. Query `GET /v1/models` and record every old-to-new model mapping.
4. Adapt OpenRouter-only routing options or response fields in one compatibility module.
5. Run the health, models, non-streaming, streaming, and failure-path checks below.
6. Report changed files, secret-name changes, model mappings, test evidence, parity gaps, and the rollback switch.

For a reusable workflow, install or invoke the repository's [OpenRouter to Phaseo migration skill](https://github.com/phaseoteam/Phaseo/tree/main/.agents/skills/openrouter-to-phaseo-migration). It packages the inventory, mapping, validation, reporting, and rollback requirements for coding agents.

## 5) Roll out safely

Use a staged rollout: dev first, then a small production slice, then full traffic once metrics are stable.

1. Start with internal traffic only.
2. Move to 5-10% production traffic and compare quality, latency, and cost metrics.
3. Promote to 100% only after parity is confirmed.
4. Keep rollback as a config-only endpoint/key switch until the cutover is stable.

## Validation commands

```bash theme={null}
curl -s "https://api.phaseo.app/v1/health"
curl -s "https://api.phaseo.app/v1/models" -H "Authorization: Bearer $PHASEO_API_KEY"
curl -s "https://api.phaseo.app/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $PHASEO_API_KEY" \
  -d '{"model":"openai/gpt-4.1-mini","messages":[{"role":"user","content":"Say hello"}]}'
```

Test streaming separately through the same endpoint:

```bash theme={null}
curl -N "https://api.phaseo.app/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $PHASEO_API_KEY" \
  -d '{"model":"openai/gpt-4.1-mini","stream":true,"messages":[{"role":"user","content":"Reply with: stream works"}]}'
```

Confirm that your application also handles an invalid model without exposing credentials:

```bash theme={null}
curl -s "https://api.phaseo.app/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $PHASEO_API_KEY" \
  -d '{"model":"invalid/migration-test","messages":[{"role":"user","content":"test"}]}'
```

Then:

* Run one streaming request through your app-level integration test.
* Run one negative test for invalid key or invalid model.
* Replay a small golden prompt set and compare outputs to baseline.

## Next steps

* [Get free help migrating your OpenRouter integration](https://phaseo.app/contact)
* [Open the interactive OpenRouter migration guide](https://phaseo.app/migrate/openrouter)
* [Compare Phaseo and OpenRouter](https://phaseo.app/compare/openrouter)
* [Quickstart](https://phaseo.app/docs/v1/quickstart.md)
* [API Reference: Models](https://phaseo.app/docs/v1/api-reference/endpoint/models.md)
* [Examples](https://phaseo.app/docs/v1/guides/examples.md)
* [Error Handling](https://phaseo.app/docs/v1/api-reference/errors.md)


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