> ## 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.

# Integrations: connect your tools to ModuleX

> Connect ModuleX to 175 services and call their tools from your workflows and the Assistant. Learn what integrations are, browse the catalog, and connect credentials with OAuth or your own keys.

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>;
};

An integration is how ModuleX talks to a service you already use — GitHub, Slack, Gmail, Notion, Salesforce, and many more. Once a service is connected, ModuleX can run its actions for you: open an issue, send a message, read a row, create a contact. You connect the service once, and every workflow and the [Assistant](/assistant/overview) can use it from then on.

<MediaEmbed id="MX-MEDIA-4000" type="screenshot" caption={"The ModuleX integration catalog: a grid of integration cards with logos, names, and a category filter."} />

## Integrations and tools, in plain terms

Two words come up everywhere in ModuleX. They are easy to keep straight.

<CardGroup cols={2}>
  <Card title="An integration" icon="plug">
    A connection to one external service — for example **GitHub** or **Slack**. It bundles the service's logo, its actions, and how to authenticate to it.
  </Card>

  <Card title="A tool" icon="wrench">
    One callable action a connected integration exposes — for example "create an issue" or "send a message." A single integration usually offers many tools.
  </Card>
</CardGroup>

So you connect an **integration** once, and that unlocks all of its **tools**. ModuleX ships **175 integrations** today, and together they expose 600+ tool actions you can call.

<Note>
  ModuleX has **175 integrations** as of this writing. You may see other counts in older material — this is the current, verified figure.
</Note>

## Where you use integration tools

A connected tool is available in two places, and you do not have to choose up front.

<CardGroup cols={2}>
  <Card title="In a workflow" icon="workflow" href="/workflow-builder/nodes/tool">
    Drop a [tool node](/workflow-builder/nodes/tool) onto the canvas, pick the integration and the action, and the workflow calls it on every run. This is the reusable, repeatable path.
  </Card>

  <Card title="In the Assistant" icon="bot" href="/assistant/overview">
    Ask the [Assistant](/assistant/overview) in plain language. It finds the right tool among your connected integrations, calls it for you, and pauses for approval when an action is sensitive.
  </Card>
</CardGroup>

The catalog is shared. A service you connect for the Assistant is the same connection a workflow uses, and the credentials you store work for both.

## Browse the catalog

The catalog is the home for every integration ModuleX can connect to. You can search by name and filter by category to find what you need.

<Card title="Open the integration catalog" icon="grid" href="/integrations/catalog">
  Browse all 175 integrations by category, see each one's logo and description, and find the tools it offers.
</Card>

<Note>
  Categories in the catalog are descriptive labels (such as productivity, developer tools, marketing, and CRM), and a single integration can appear under more than one. Use the search box if you already know the service you want.
</Note>

## Connect a service: credentials and BYOK

Before ModuleX can act on your behalf, you tell it how to authenticate to the service. ModuleX stores that connection as an encrypted **credential** scoped to your [organization](/concepts/organizations-roles), so your whole team can reuse it without re-entering secrets.

There are two ways a service authenticates, depending on what it supports.

<CardGroup cols={2}>
  <Card title="OAuth (connect with a click)" icon="key">
    For services that support it, you click **Connect**, sign in on the provider's own page, and approve access. ModuleX never sees your password — it receives a scoped token. Many connectors use this flow, with PKCE where the provider supports it.
  </Card>

  <Card title="Bring your own key (BYOK)" icon="lock">
    For services that use API keys, you paste a key (or other fields the service needs) into ModuleX. The same idea applies to model and knowledge providers: connect your own provider account and your usage is billed directly by that provider, with no ModuleX markup.
  </Card>
</CardGroup>

Under the hood, an integration declares one or more **auth schemas**, and ModuleX shows you the right form for each. There are six schema variants in total — OAuth2, bearer token, API key, a ModuleX-managed key, custom, and internal — but as a user you simply see the connect button or the fields a service asks for.

<Card title="How authentication and credentials work" icon="shield-check" href="/integrations/authentication">
  See the full picture: OAuth flows, API keys, BYOK, and how ModuleX stores and resolves your credentials.
</Card>

<Note>
  ModuleX-managed model and knowledge usage is metered in [credits](/concepts/credits-billing). BYOK usage is billed by the provider you connected, not by ModuleX. See [credits and the billing model](/concepts/credits-billing) for the details.
</Note>

## Use a tool in a workflow

Connecting a service and using one of its tools takes a few steps. Here is the path from zero to a running tool call.

<Steps>
  <Step title="Find the integration in the catalog">
    Open the [catalog](/integrations/catalog), search for the service you want, and open it to see the tools it offers.
  </Step>

  <Step title="Connect it">
    Click **Connect** and either approve the OAuth flow or paste your API key. ModuleX saves the credential to your organization so it is reusable. See [authentication and credentials](/integrations/authentication).
  </Step>

  <Step title="Add a tool node to your workflow">
    In the [workflow builder](/workflow-builder/overview), add a [tool node](/workflow-builder/nodes/tool), then pick the integration and the specific action you want to run.
  </Step>

  <Step title="Map the inputs">
    Fill in the action's parameters, pulling values from earlier nodes with references such as `{{node_id.field}}` where you need them.
  </Step>

  <Step title="Run it">
    Run the workflow. The tool node calls the service, and its result is written into run state for the next node to use.
  </Step>
</Steps>

<Card title="The tool node, in depth" icon="wrench" href="/workflow-builder/nodes/tool">
  Learn how the tool node selects an action, maps parameters, and returns results inside a workflow.
</Card>

## Call a tool from your own code

You can also list the catalog programmatically — for example to discover which integrations exist before wiring up a run. Every request authenticates with `Authorization: Bearer mx_live_…` plus your `X-Organization-ID` header. See [authentication](/api-reference/authentication).

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.modulex.dev/integrations/tools \
    -H "Authorization: Bearer mx_live_your_api_key" \
    -H "X-Organization-ID: org_your_organization_id"
  ```

  ```python Python theme={null}
  import httpx

  resp = httpx.get(
      "https://api.modulex.dev/integrations/tools",
      headers={
          "Authorization": "Bearer mx_live_your_api_key",
          "X-Organization-ID": "org_your_organization_id",
      },
  )
  for integration in resp.json():
      print(integration["name"], "-", integration["display_name"])
  ```

  ```javascript JavaScript theme={null}
  const resp = await fetch("https://api.modulex.dev/integrations/tools", {
    headers: {
      Authorization: "Bearer mx_live_your_api_key",
      "X-Organization-ID": "org_your_organization_id",
    },
  });
  const integrations = await resp.json();
  for (const integration of integrations) {
    console.log(integration.name, "-", integration.display_name);
  }
  ```
</CodeGroup>

The catalog endpoint returns a list of integrations, each with its `name`, `display_name`, `description`, and categories:

```json Response theme={null}
[
  {
    "name": "github",
    "display_name": "GitHub",
    "description": "GitHub repository and code management platform",
    "logo": "modulex:github-themed",
    "categories": ["Developer Tools & Infrastructure"],
    "integration_type": "tool",
    "version": "1.0.0"
  }
]
```

<Note>
  Listing the catalog requires the **owner** or **admin** role in the organization you pass in `X-Organization-ID`. The retired `member` role is not a current role — see [roles and permissions](/security/roles-permissions).
</Note>

## A note on installing the package

If you are running ModuleX yourself, the integrations ship in a Python package that the runtime loads at startup. Installing it pulls in the core dependencies only.

<Warning>
  ModuleX does **not** currently provide working install extras such as `[all]` or per-tool extras like `[github,slack]`. Those groups are not populated yet, so asking for them only emits a pip warning and installs the core package. Install the base package, then add any extra SDKs a specific tool needs by hand. See [installing and using integrations](/integrations/install) for the current, accurate steps.
</Warning>

## Where to go next

<CardGroup cols={2}>
  <Card title="Integration catalog" icon="grid" href="/integrations/catalog">
    Browse all 175 integrations by category and find the tools you need.
  </Card>

  <Card title="Authentication & credentials" icon="key" href="/integrations/authentication">
    Connect a service with OAuth or your own API key, and learn how ModuleX stores credentials.
  </Card>

  <Card title="The tool node" icon="wrench" href="/workflow-builder/nodes/tool">
    Call a connected integration's action from inside a workflow.
  </Card>

  <Card title="Connect an integration" icon="circle-play" href="/guides/connect-an-integration">
    A step-by-step walkthrough: connect a service and call its tool from a workflow.
  </Card>
</CardGroup>
