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

# Build model and provider fallback with RunBridge AI

> Keep RunBridge AI as the primary route, switch models inside RunBridge AI first, and use an official provider as an optional final fallback.

Build two fallback layers for text requests. Keep RunBridge AI as the primary
route. First, change the model ID inside RunBridge AI. If those routes fail and
official fallback is enabled, call the matching official provider.

<CardGroup cols={2}>
  <Card title="Model fallback inside RunBridge AI" icon="shuffle">
    Keep the same RunBridge AI API key and base URL. Try a compatible secondary
    model ID after the primary model fails.
  </Card>

  <Card title="Official-provider fallback" icon="arrow-right-arrow-left">
    Use a separate OpenAI or Anthropic client, API key, model ID, account, and
    billing configuration.
  </Card>
</CardGroup>

The recommended order is `RunBridge AI primary model → RunBridge AI fallback model →
matching official provider`.

## Decide when to fallback

Use a narrow error policy so that fallback does not hide request problems:

| Failure | Use the next route? |
| - | - |
| Connection error, timeout, `408`, `429`, or temporary `5xx` | Yes. Try the next configured route. |
| Verified model-unavailable, balance, or quota signal | Add that exact signal to the classifier before you use it |
| Invalid request, invalid API key, or unsupported parameter | No. Fix the request or configuration. |

The examples below use `ENABLE_OFFICIAL_FALLBACK` as the explicit switch. If
you also fallback on a model or account limit, add only its verified error
signal to your application's error classifier.

Install `openai` and `anthropic` for Python, or install `openai` and
`@anthropic-ai/sdk` for Node.js. Then configure these environment variables:

* **OpenAI route:** `RUNBRIDGE_API_KEY`, `RUNBRIDGE_OPENAI_PRIMARY_MODEL`,
  `RUNBRIDGE_OPENAI_FALLBACK_MODEL`, `OPENAI_API_KEY`, and
  `OPENAI_OFFICIAL_MODEL`
* **Claude route:** `RUNBRIDGE_API_KEY`, `RUNBRIDGE_CLAUDE_PRIMARY_MODEL`,
  `RUNBRIDGE_CLAUDE_FALLBACK_MODEL`, `ANTHROPIC_API_KEY`, and
  `ANTHROPIC_OFFICIAL_MODEL`
* **Shared controls:** `ENABLE_OFFICIAL_FALLBACK` and `ROUTE_TIMEOUT_MS`

`ENABLE_OFFICIAL_FALLBACK` defaults to `false`. Set it to `true` only when the
official-provider account is ready.

`ROUTE_TIMEOUT_MS` is the timeout for each attempt and defaults to 30 seconds.
Set it from your application's latency budget; total fallback time can include
all three attempts.

Choose fallback models that support the same request format and the capabilities
that your application requires. Test every route before you depend on it.

<Warning>
  Official-provider requests use a separate account and billing configuration.
  Configure provider budgets and alerts before you enable this route. Record the
  official fallback rate so that you can investigate sustained usage.
</Warning>

## Implement the fallback chain

Choose the tab that matches the request format that your application uses.
Configure separate model IDs for the RunBridge AI and official-provider routes.

<Tabs>
  <Tab title="OpenAI models">
    Use Chat Completions for both RunBridge AI and the OpenAI official API. The request
    shape stays the same, but each route has its own client, API key, and model ID.

    <CodeGroup>
      ```python Python theme={null}
      import os

      from openai import APIError, OpenAI

      official_fallback_enabled = (
          os.getenv("ENABLE_OFFICIAL_FALLBACK", "false").lower() == "true"
      )
      route_timeout = int(os.getenv("ROUTE_TIMEOUT_MS", "30000")) / 1000

      runbridge = OpenAI(
          api_key=os.environ["RUNBRIDGE_API_KEY"],
          base_url="https://api.runbridge.ai/v1",
          max_retries=0,
          timeout=route_timeout,
      )
      routes = [
          (
              "runbridge-primary",
              runbridge,
              os.environ["RUNBRIDGE_OPENAI_PRIMARY_MODEL"],
          ),
          (
              "runbridge-fallback",
              runbridge,
              os.environ["RUNBRIDGE_OPENAI_FALLBACK_MODEL"],
          ),
      ]
      if official_fallback_enabled:
          routes.append(
              (
                  "openai-official",
                  OpenAI(
                      api_key=os.environ["OPENAI_API_KEY"],
                      base_url="https://api.openai.com/v1",
                      max_retries=0,
                      timeout=route_timeout,
                  ),
                  os.environ["OPENAI_OFFICIAL_MODEL"],
              )
          )


      def should_fallback(error: APIError) -> bool:
          status = getattr(error, "status_code", None)
          code = getattr(error, "code", None)
          return (
              status is None
              or status in {408, 429}
              or (
                  status >= 500
                  and code not in {"invalid_request", "invalid_request_error"}
              )
          )


      def complete(messages: list[dict]) -> dict:
          for index, (route, client, model) in enumerate(routes):
              try:
                  response = client.chat.completions.create(
                      model=model,
                      messages=messages,
                  )
                  return {
                      "text": response.choices[0].message.content,
                      "route": route,
                      "model": model,
                  }
              except APIError as error:
                  if index == len(routes) - 1 or not should_fallback(error):
                      raise

          raise RuntimeError("No fallback route completed.")


      result = complete(
          [{"role": "user", "content": "Summarize RunBridge AI in one sentence."}]
      )
      print(result)
      ```

      ```javascript Node.js theme={null}
      import OpenAI from "openai";

      function requiredEnv(name) {
        const value = process.env[name];
        if (!value) {
          throw new Error(`${name} is required.`);
        }
        return value;
      }

      const officialFallbackEnabled =
        process.env.ENABLE_OFFICIAL_FALLBACK === "true";
      const routeTimeout = Number(process.env.ROUTE_TIMEOUT_MS ?? 30000);

      const runbridge = new OpenAI({
        apiKey: requiredEnv("RUNBRIDGE_API_KEY"),
        baseURL: "https://api.runbridge.ai/v1",
        maxRetries: 0,
        timeout: routeTimeout,
      });
      const routes = [
        {
          route: "runbridge-primary",
          client: runbridge,
          model: requiredEnv("RUNBRIDGE_OPENAI_PRIMARY_MODEL"),
        },
        {
          route: "runbridge-fallback",
          client: runbridge,
          model: requiredEnv("RUNBRIDGE_OPENAI_FALLBACK_MODEL"),
        },
      ];
      if (officialFallbackEnabled) {
        routes.push({
          route: "openai-official",
          client: new OpenAI({
            apiKey: requiredEnv("OPENAI_API_KEY"),
            baseURL: "https://api.openai.com/v1",
            maxRetries: 0,
            timeout: routeTimeout,
          }),
          model: requiredEnv("OPENAI_OFFICIAL_MODEL"),
        });
      }

      function shouldFallback(error) {
        if (!(error instanceof OpenAI.APIError)) {
          throw error;
        }

        return (
          error.status === undefined ||
          error.status === 408 ||
          error.status === 429 ||
          (error.status >= 500 &&
            !["invalid_request", "invalid_request_error"].includes(error.code))
        );
      }

      async function complete(messages) {
        for (const [index, { route, client, model }] of routes.entries()) {
          try {
            const response = await client.chat.completions.create({
              model,
              messages,
            });
            return {
              text: response.choices[0].message.content,
              route,
              model,
            };
          } catch (error) {
            if (index === routes.length - 1 || !shouldFallback(error)) {
              throw error;
            }
          }
        }

        throw new Error("No fallback route completed.");
      }

      const result = await complete([
        { role: "user", content: "Summarize RunBridge AI in one sentence." },
      ]);
      console.log(result);
      ```
    </CodeGroup>

    If your application uses the Responses API, keep the same dual-client routing
    pattern and adapt the request and response fields. See the official
    [Chat Completions reference](https://developers.openai.com/api/reference/resources/chat/subresources/completions/methods/create).
  </Tab>

  <Tab title="Claude models">
    Use the Anthropic Messages request format for both RunBridge AI and the Anthropic
    official API. This avoids converting between OpenAI-compatible messages and
    Anthropic content blocks during fallback.

    <CodeGroup>
      ```python Python theme={null}
      import os

      import anthropic

      official_fallback_enabled = (
          os.getenv("ENABLE_OFFICIAL_FALLBACK", "false").lower() == "true"
      )
      route_timeout = int(os.getenv("ROUTE_TIMEOUT_MS", "30000")) / 1000

      runbridge = anthropic.Anthropic(
          api_key=os.environ["RUNBRIDGE_API_KEY"],
          auth_token=None,
          base_url="https://api.runbridge.ai",
          max_retries=0,
          timeout=route_timeout,
      )
      routes = [
          (
              "runbridge-primary",
              runbridge,
              os.environ["RUNBRIDGE_CLAUDE_PRIMARY_MODEL"],
          ),
          (
              "runbridge-fallback",
              runbridge,
              os.environ["RUNBRIDGE_CLAUDE_FALLBACK_MODEL"],
          ),
      ]
      if official_fallback_enabled:
          routes.append(
              (
                  "anthropic-official",
                  anthropic.Anthropic(
                      api_key=os.environ["ANTHROPIC_API_KEY"],
                      auth_token=None,
                      base_url="https://api.anthropic.com",
                      max_retries=0,
                      timeout=route_timeout,
                  ),
                  os.environ["ANTHROPIC_OFFICIAL_MODEL"],
              )
          )


      def should_fallback(error: anthropic.APIError) -> bool:
          status = getattr(error, "status_code", None)
          body = getattr(error, "body", {}) or {}
          details = body.get("error", {}) if isinstance(body, dict) else {}
          code = details.get("code") or details.get("type")
          return (
              status is None
              or status in {408, 429}
              or (
                  status >= 500
                  and code not in {"invalid_request", "invalid_request_error"}
              )
          )


      def text_from_message(message) -> str:
          return "".join(
              block.text for block in message.content if block.type == "text"
          )


      def complete(messages: list[dict]) -> dict:
          for index, (route, client, model) in enumerate(routes):
              try:
                  response = client.messages.create(
                      model=model,
                      max_tokens=512,
                      messages=messages,
                  )
                  return {
                      "text": text_from_message(response),
                      "route": route,
                      "model": model,
                  }
              except anthropic.APIError as error:
                  if index == len(routes) - 1 or not should_fallback(error):
                      raise

          raise RuntimeError("No fallback route completed.")


      result = complete(
          [{"role": "user", "content": "Summarize RunBridge AI in one sentence."}]
      )
      print(result)
      ```

      ```javascript Node.js theme={null}
      import Anthropic from "@anthropic-ai/sdk";

      function requiredEnv(name) {
        const value = process.env[name];
        if (!value) {
          throw new Error(`${name} is required.`);
        }
        return value;
      }

      const officialFallbackEnabled =
        process.env.ENABLE_OFFICIAL_FALLBACK === "true";
      const routeTimeout = Number(process.env.ROUTE_TIMEOUT_MS ?? 30000);

      const runbridge = new Anthropic({
        apiKey: requiredEnv("RUNBRIDGE_API_KEY"),
        authToken: null,
        baseURL: "https://api.runbridge.ai",
        maxRetries: 0,
        timeout: routeTimeout,
      });
      const routes = [
        {
          route: "runbridge-primary",
          client: runbridge,
          model: requiredEnv("RUNBRIDGE_CLAUDE_PRIMARY_MODEL"),
        },
        {
          route: "runbridge-fallback",
          client: runbridge,
          model: requiredEnv("RUNBRIDGE_CLAUDE_FALLBACK_MODEL"),
        },
      ];
      if (officialFallbackEnabled) {
        routes.push({
          route: "anthropic-official",
          client: new Anthropic({
            apiKey: requiredEnv("ANTHROPIC_API_KEY"),
            authToken: null,
            baseURL: "https://api.anthropic.com",
            maxRetries: 0,
            timeout: routeTimeout,
          }),
          model: requiredEnv("ANTHROPIC_OFFICIAL_MODEL"),
        });
      }

      function shouldFallback(error) {
        if (!(error instanceof Anthropic.APIError)) {
          throw error;
        }

        const details = error.error?.error ?? error.error ?? {};
        const code = details.code ?? details.type ?? error.type;
        return (
          error.status === undefined ||
          error.status === 408 ||
          error.status === 429 ||
          (error.status >= 500 &&
            !["invalid_request", "invalid_request_error"].includes(code))
        );
      }

      function textFromMessage(message) {
        return message.content
          .filter((block) => block.type === "text")
          .map((block) => block.text)
          .join("");
      }

      async function complete(messages) {
        for (const [index, { route, client, model }] of routes.entries()) {
          try {
            const response = await client.messages.create({
              model,
              max_tokens: 512,
              messages,
            });
            return {
              text: textFromMessage(response),
              route,
              model,
            };
          } catch (error) {
            if (index === routes.length - 1 || !shouldFallback(error)) {
              throw error;
            }
          }
        }

        throw new Error("No fallback route completed.");
      }

      const result = await complete([
        { role: "user", content: "Summarize RunBridge AI in one sentence." },
      ]);
      console.log(result);
      ```
    </CodeGroup>

    For the complete request and response format, see the official
    [Anthropic Messages reference](https://platform.claude.com/docs/en/api/messages/create).
  </Tab>
</Tabs>

## Switch between model families

GPT and Claude can fallback to each other when your application converts both
requests to shared fields, normalizes both responses, and verifies the required
capabilities on every route. A model ID change alone is not enough when request
or response shapes differ.

## Related links

* [Error codes and retry strategy](/guides/error-codes-and-retry-strategy)
* [Chat Completions](/api/text/chat)
* [Anthropic Messages](/api/text/anthropic-messages)
* [Models page](/overview/models)
* [Pricing](https://runbridge.ai/pricing/)

<script type="application/ld+json">
  {`
    {
    "@context": "https://schema.org",
    "@graph": [
      {
        "@type": "TechArticle",
        "@id": "https://runbridge.mintlify.site/guides/model-fallback-with-runbridge",
        "headline": "Build model and provider fallback with RunBridge AI",
        "description": "Keep RunBridge AI as the primary route, switch models inside RunBridge AI first, and use an official provider as an optional final fallback.",
        "keywords": [
          "RunBridge AI model fallback",
          "provider fallback",
          "OpenAI fallback",
          "Anthropic fallback",
          "API resilience"
        ],
        "url": "https://runbridge.mintlify.site/guides/model-fallback-with-runbridge",
        "author": {
          "@type": "Organization",
          "name": "RunBridge AI"
        },
        "publisher": {
          "@type": "Organization",
          "name": "RunBridge AI",
          "url": "https://runbridge.ai"
        }
      },
      {
        "@type": "BreadcrumbList",
        "itemListElement": [
          {
            "@type": "ListItem",
            "position": 1,
            "name": "RunBridge AI Docs",
            "item": "https://runbridge.mintlify.site/"
          },
          {
            "@type": "ListItem",
            "position": 2,
            "name": "Guides",
            "item": "https://runbridge.mintlify.site/guides/use-runbridge-with-openai-sdk"
          },
          {
            "@type": "ListItem",
            "position": 3,
            "name": "Build model and provider fallback with RunBridge AI",
            "item": "https://runbridge.mintlify.site/guides/model-fallback-with-runbridge"
          }
        ]
      }
    ]
    }
    `}
</script>


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