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

# Choosing a model for chat

> Pick the language model behind a ModuleX chat — ModuleX-managed models billed in credits or your own provider key (BYOK) — and understand how per-organization availability is decided.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

The model is the language model that powers a chat — it reads your message, decides which tools to call, and writes the reply. ModuleX lets you choose that model per chat, and your organization decides which models are on the menu in the first place.

This page covers the three things worth knowing: how to pick a model, the difference between ModuleX-managed models and bringing your own key (BYOK), and why your list of models can differ from a teammate's.

<Note>
  Choosing a model here changes the model for the [Assistant](/concepts/assistant) — the chat that uses your connected tools to get work done. For the full provider reference (OpenAI, Anthropic, Google Gemini, xAI Grok, and ModuleX-managed), see [LLM providers](/integrations/llm-providers/overview).
</Note>

## Pick a model

Every chat runs on one model at a time. You pick it from the model selector next to the message box before you send, and you can switch models between turns in the same chat.

<Steps>
  <Step title="Open the model selector">
    In a [chat](/platform/chat/overview), open the model selector beside the composer. It lists the models your organization has turned on, grouped by provider.
  </Step>

  <Step title="Choose a model">
    Pick the model you want. Each entry shows its display name and provider so you can tell a ModuleX-managed model apart from one connected with your own key.
  </Step>

  <Step title="Send your message">
    Send as usual. The model you chose handles this turn. If you do nothing, the chat uses your organization's default model.
  </Step>

  <Step title="Switch any time">
    Change the model and send again to use a different model for the next turn. Your choice is a per-session override — it does not change the organization default.
  </Step>
</Steps>

<MediaEmbed id="MX-MEDIA-3320" type="screenshot" caption={"The chat model selector open, showing models grouped by provider with managed and BYOK entries."} />

### Three layers decide which model runs

You rarely have to think about this, but it explains why a chat behaves the way it does. ModuleX resolves the model for a turn from three layers, most specific first:

<CardGroup cols={3}>
  <Card title="Your session choice" icon="hand-pointer">
    The model you picked in the selector for this chat. It wins when it is set, and it lasts for the session only.
  </Card>

  <Card title="Organization default" icon="building">
    The model your organization saved as the default. It is used whenever you have not picked one.
  </Card>

  <Card title="The run's model" icon="lock">
    Once a turn starts, it stays on the model it began with — including when a paused chat resumes. Changing the selector affects the next turn, not the one already running.
  </Card>
</CardGroup>

In practice: pick a model and it is used; leave it alone and the organization default is used; a turn already in flight keeps its own model to the end.

## Managed models vs your own key (BYOK)

Models come from two kinds of sources, and the difference shows up on your bill.

<CardGroup cols={2}>
  <Card title="ModuleX-managed models" icon="box-check">
    The default. The model runs through ModuleX-provisioned providers, so there is nothing to connect — it works out of the box. Usage is metered in [credits](/billing/credits). On the wire these models belong to the `modulexai` provider.
  </Card>

  <Card title="Bring your own key (BYOK)" icon="key">
    Connect your own provider account — [OpenAI](/integrations/llm-providers/openai), [Anthropic](/integrations/llm-providers/anthropic), [Google Gemini](/integrations/llm-providers/gemini), or [xAI Grok](/integrations/llm-providers/xai) — and ModuleX calls the model with your key. The provider bills you directly, with no ModuleX markup.
  </Card>
</CardGroup>

### How they compare

|                                   | ModuleX-managed                                | BYOK                                                |
| --------------------------------- | ---------------------------------------------- | --------------------------------------------------- |
| Setup                             | None — available by default                    | Connect a provider credential first                 |
| Billing                           | Metered in ModuleX [credits](/billing/credits) | Billed by the provider, no ModuleX markup           |
| Counts toward your credit balance | Yes                                            | No — BYOK usage is not credited                     |
| Provider on the wire              | `modulexai`                                    | The provider you connected, for example `openai`    |
| Best for                          | Getting started fast and a single bill         | Existing provider contracts and direct cost control |

<Warning>
  BYOK usage is **not** credited — it is billed directly by your provider and appears in ModuleX analytics for visibility only. ModuleX-managed usage is the only kind that draws down your credit balance. For what a credit is and exactly what consumes one, see [Credits & metering](/billing/credits).
</Warning>

<Note>
  To use a BYOK model you first connect that provider's account as a credential. Start at [LLM providers](/integrations/llm-providers/overview), then follow [Authentication & credentials](/integrations/authentication). Once connected, the model appears in your chat selector. The default managed option is documented at [ModuleX-managed models](/integrations/llm-providers/modulexai).
</Note>

## Per-organization availability

The selector does not show every model that exists — it shows the models your organization has turned on. Two people in different organizations, or even in the same one at different times, can see different lists.

<AccordionGroup>
  <Accordion title="Who controls the list" icon="user-shield">
    Model availability is an organization-level setting managed by an organization **owner or admin**. They choose which models are visible to the organization and which model is the saved default. Other roles use whatever the owner or admin has enabled. (The legacy `member` role has been retired — only `owner` and `admin` exist. See [Roles & permissions](/security/roles-permissions).)
  </Accordion>

  <Accordion title="Active vs inactive models" icon="toggle-on">
    ModuleX keeps two groups per organization: active models, which appear in the selector, and inactive models, which are hidden. Owners and admins move models between the two. A model you connected with your own key still has to be active to appear.
  </Accordion>

  <Accordion title="Why your list can differ" icon="users">
    Your list reflects your current organization's choices. Switch organizations and the selector — along with the default model — changes to match. A BYOK model also only appears once the matching provider credential exists in that organization.
  </Accordion>

  <Accordion title="Deprecated models" icon="triangle-alert">
    A model can be marked deprecated by its provider. When that happens ModuleX points to a successor model so you can move over. Prefer the current model when you see a deprecation note.
  </Accordion>
</AccordionGroup>

<MediaEmbed id="MX-MEDIA-3321" type="screenshot" caption={"The organization settings screen where an owner or admin turns models on or off and sets the default model."} />

## Setting a model from the API

Most people pick a model in the app. If you drive a chat over the API, you pass the model in the `llm` object when you send a turn. Omit `llm` and the chat falls back to your organization's default model.

The `llm` object has four fields: `integration_name`, `provider_id`, and `model_id` are required, and `credential_id` is optional (used to point at a specific BYOK credential). Authenticate with `Authorization: Bearer mx_live_…` and `X-Organization-ID`, the same as every ModuleX request.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.modulex.dev/assistant/chat \
    -H "Authorization: Bearer mx_live_8f2c4a1e9b7d6f3a0c5e2d1b" \
    -H "X-Organization-ID: org_3a7f9c2e1d4b" \
    -H "Content-Type: application/json" \
    -d '{
      "message": "Summarize my open GitHub issues",
      "llm": {
        "integration_name": "openai",
        "provider_id": "openai",
        "model_id": "gpt-4o"
      }
    }'
  ```

  ```python Python theme={null}
  from modulex import ModuleX

  client = ModuleX(
      api_key="mx_live_8f2c4a1e9b7d6f3a0c5e2d1b",
      organization_id="org_3a7f9c2e1d4b",
  )

  response = client.assistant.chat(
      message="Summarize my open GitHub issues",
      llm={
          "integration_name": "openai",
          "provider_id": "openai",
          "model_id": "gpt-4o",
      },
  )
  ```

  ```javascript JavaScript theme={null}
  import { ModuleX } from "@modulex/sdk";

  const client = new ModuleX({
    apiKey: "mx_live_8f2c4a1e9b7d6f3a0c5e2d1b",
    organizationId: "org_3a7f9c2e1d4b",
  });

  const response = await client.assistant.chat({
    message: "Summarize my open GitHub issues",
    llm: {
      integration_name: "openai",
      provider_id: "openai",
      model_id: "gpt-4o",
    },
  });
  ```
</CodeGroup>

<Note>
  The Assistant chat endpoints require an **owner or admin** role in the organization. A request from a non-admin is rejected. To answer a paused chat that is waiting on you (human-in-the-loop), you pass the same `llm` object again on resume so the model can be rebuilt — see [Human-in-the-loop](/assistant/human-in-the-loop).
</Note>

<Warning>
  Sending a chat turn is gated by billing on the run surface. If your plan's credits are exhausted, your wallet cannot cover overage, or you hit a rate limit, the request is rejected with a `402`, `403`, or `429` carrying a flat denial body — for example `{code, layer, key, current, limit, reason}`. BYOK usage still counts as a turn for rate limiting even though it is not credited. See [Usage gating & limits](/billing/usage-gating) and [Errors & status codes](/api-reference/errors).
</Warning>

## What to pick

<CardGroup cols={2}>
  <Card title="Just getting started" icon="rocket" href="/platform/chat/overview">
    Use a ModuleX-managed model and skip setup. Usage is metered in credits and there is nothing to connect.
  </Card>

  <Card title="You have a provider account" icon="key" href="/integrations/llm-providers/overview">
    Connect your own key (BYOK) to use your existing provider and be billed directly, with no ModuleX markup.
  </Card>

  <Card title="You manage the organization" icon="sliders" href="/security/roles-permissions">
    As an owner or admin, choose which models your team can use and set the default model for everyone.
  </Card>

  <Card title="You want the cost details" icon="coins" href="/billing/credits">
    See exactly what a credit is and what managed model usage consumes.
  </Card>
</CardGroup>

## Related pages

<CardGroup cols={2}>
  <Card title="LLM providers" icon="server" href="/integrations/llm-providers/overview">
    The full provider reference — managed and BYOK — and the models each one offers.
  </Card>

  <Card title="Assistant models & settings" icon="robot" href="/assistant/models-and-settings">
    Choose the model and configure how the Assistant behaves.
  </Card>

  <Card title="Chat overview" icon="messages" href="/platform/chat/overview">
    The chat surface for talking to the Assistant, running workflows, and querying knowledge.
  </Card>

  <Card title="Credits & the billing model" icon="receipt" href="/concepts/credits-billing">
    How managed usage is metered and where the billing gate applies.
  </Card>
</CardGroup>
