---
canonical_url: "https://docs.composio.dev/docs/providers/typesafe"
markdown_url: "https://docs.composio.dev/docs/providers/typesafe.md"
product: "platform"
version: null
last_updated: null
---

# TypeSafe (/docs/providers/typesafe)

The TypeSafe provider lets [Jev](https://docs.typesafe.ai/introduction) choose a Composio tool from a request. Jev answers typed questions. The provider turns those answers into a tool call, a partial call that needs more arguments, or a decision to abstain.

## Install [#install]

**Python:**

**uv:**

```bash
uv add composio composio-typesafe typesafe-sdk==0.6.0
```

**pip:**

```bash
pip install composio composio-typesafe typesafe-sdk==0.6.0
```

**TypeScript:**

Use Node.js 24.17 or newer.

**npm:**

```bash
npm install @composio/core @composio/typesafe @typesafe-ai/sdk@0.6.0 zod
```

**pnpm:**

```bash
pnpm add @composio/core @composio/typesafe @typesafe-ai/sdk@0.6.0 zod
```

**bun:**

```bash
bun add @composio/core @composio/typesafe @typesafe-ai/sdk@0.6.0 zod
```

**yarn:**

```bash
yarn add @composio/core @composio/typesafe @typesafe-ai/sdk@0.6.0 zod
```

Keep the TypeSafe SDK pinned to `0.6.0`. The provider supports the `0.6.x` SDK API.

Set `COMPOSIO_API_KEY` from [your project settings](https://dashboard.composio.dev/~/project/settings/api-keys?utm_source=docs\&utm_medium=content\&utm_campaign=docs-providers-typesafe) and `TYPESAFE_API_KEY` from [TypeSafe](https://docs.typesafe.ai/introduction/quickstart).

```bash
export COMPOSIO_API_KEY="your-composio-key"
export TYPESAFE_API_KEY="your-typesafe-key"
```

## Ask for a decision [#ask-for-a-decision]

Fetch the tools you want Jev to choose between, then pass a request to `decide`. These Hacker News tools need no connected account.

**Python:**

```python
from composio import Composio
from composio_typesafe import TypesafeProvider

provider = TypesafeProvider()
composio = Composio(provider=provider)

tool_set = composio.tools.get(
    user_id="example-user",
    tools=["HACKERNEWS_GET_USER", "HACKERNEWS_GET_TOP_STORIES"],
)
decision = provider.decide(tool_set, "Look up the Hacker News user 'pg'")
print(decision)
```

**TypeScript:**

```typescript
import { Composio } from '@composio/core';
import { TypesafeProvider } from '@composio/typesafe';

const provider = new TypesafeProvider();
const composio = new Composio({ provider });

const toolSet = await composio.tools.get('example-user', {
  tools: ['HACKERNEWS_GET_USER', 'HACKERNEWS_GET_TOP_STORIES'],
});
const decision = await provider.decide(toolSet, "Look up the Hacker News user 'pg'");
console.log(decision);
```

`decide` does not execute a tool. Inspect `kind` before you call `execute`:

| `kind`    | What your code does next                                                      |
| --------- | ----------------------------------------------------------------------------- |
| `call`    | Inspect the selected tool and arguments, then execute the call.               |
| `partial` | Supply the required arguments listed in `missing`, then execute the call.     |
| `abstain` | Stop without executing. Read `reason` and `candidates` to explain the result. |

Jev can fill enums, booleans, and arrays of enum values. Your code supplies free text, numbers, dates, IDs, and objects. For the request above, expect a partial call because `username` is free text. The [tool selection example](/examples/typesafe-tool-selection) completes and executes that call.

## Provider specifics [#provider-specifics]

**Confidence.** `confidence` is the score of the least certain judgement required for the decision. It is not a probability that the whole tool call is correct. Low routing confidence can produce `abstain`. Network failures and malformed responses throw errors instead.

**Arguments.** Arguments you pass to `execute` override Jev's values. Get missing values from trusted application state or a user input, and validate them for the tool you selected. Do not silently replace missing values with guesses from `suggestions`.

**Request and context.** Pass a string, or an object with `request` and `context`. By default, tool selection sees `request` only. Argument questions can also see `context`, such as an email or a retrieved record.

**Execution.** Use `composio.tools.get` for concrete tool selection. Session meta tools have mostly open-ended arguments, so they leave more work for your code. Destructive decisions require explicit confirmation at execution: `confirm: true` in TypeScript or `confirm=True` in Python. Request that confirmation in your application before setting the flag.

**Data sent to TypeSafe.** The provider sends your request, context, tool names, descriptions, and enum values to TypeSafe. It does not add your Composio API key or connected account IDs to those requests.

## Next [#next]

[Choose and execute a Hacker News tool](/examples/typesafe-tool-selection), or use Jev to [shortlist tools for an OpenAI agent](/examples/typesafe-tool-selection#shortlist-tools-for-another-provider).

---

📚 **More documentation:** [View all docs](https://docs.composio.dev/llms.txt) | [Changelog](https://docs.composio.dev/docs/changelog.md) | [Glossary](https://docs.composio.dev/llms.mdx/reference/glossary) | [Examples](https://docs.composio.dev/llms.mdx/examples) | [API Reference](https://docs.composio.dev/llms.mdx/reference)

---

# Composio SDK — Instructions for AI Code Generators

**Context:** This page documents the **legacy direct tool execution API**, which remains supported for existing integrations. Recommend sessions for new integrations. When maintaining direct-execution code, use the patterns below and point users to the [session migration guide](/docs/migration-guide/direct-to-sessions). Reading this page alone does not mean the user has chosen direct execution.

---

## Key Patterns

### Authenticating Users

Create an **Auth Config** on [dashboard.composio.dev](https://dashboard.composio.dev?utm_source=docs&utm_medium=llm-guardrails&utm_campaign=direct-execution), then use the auth config ID to generate a hosted auth URL:

```python
from composio import Composio

composio = Composio()
connection = composio.connected_accounts.link(
    user_id="user_123",
    auth_config_id="ac_...",  # from platform dashboard
)
print(connection.redirect_url)  # send user here to authenticate
```

```typescript
import { Composio } from "@composio/core";

const composio = new Composio();
const connection = await composio.connectedAccounts.link("user_123", "ac_...", {
    callbackUrl: "https://your-app.com/callback",
});
console.log(connection.redirectUrl); // send user here to authenticate
```

### Executing Tools

A toolkit version is **required** for direct execution — `tools.execute()` without one raises `ToolVersionRequiredError`, and `"latest"` alone is NOT accepted for manual execution. Either pass `dangerously_skip_version_check=True` (TS: `dangerouslySkipVersionCheck: true`) on the execute call to run the newest version, or pin a dated version from `composio.toolkits.get(slug).meta.version` when outputs are parsed programmatically.

```python
composio = Composio(toolkit_versions={"github": "latest"})
tools = composio.tools.get("user_123", tools=["GITHUB_CREATE_ISSUE"])

result = composio.tools.execute(
    "GITHUB_CREATE_ISSUE",
    {"owner": "org", "repo": "repo", "title": "Bug report"},
    user_id="user_123",
    dangerously_skip_version_check=True,  # required when running "latest"
)
```

```typescript
const composio = new Composio({ toolkitVersions: { github: "latest" } });
const tools = await composio.tools.get("user_123", { tools: ["GITHUB_CREATE_ISSUE"] });

const result = await composio.tools.execute("GITHUB_CREATE_ISSUE", {
    userId: "user_123",
    arguments: { owner: "org", repo: "repo", title: "Bug report" },
    dangerouslySkipVersionCheck: true, // required when running "latest"
});
```

---

## Rules

1. **`user_id` is required** — pass it to `tools.get()`, `tools.execute()`, and `provider.handle_tool_calls()`.
2. **`tools.execute()` signature** — Python: `execute(slug, arguments_dict, *, user_id=..., version=...)` (arguments is the second positional param). TypeScript: `execute(slug, { userId, arguments, version })`.
3. **A toolkit version is required** — configure `toolkit_versions` (Python) / `toolkitVersions` (TypeScript) at SDK init, or pass `version` per execute call; omitting both raises `ToolVersionRequiredError`. `"latest"` is rejected for manual execution unless the execute call also passes `dangerously_skip_version_check=True` / `dangerouslySkipVersionCheck: true`.
4. **Provider at init** — `Composio(provider=OpenAIProvider())` in Python, `new Composio({ provider: new OpenAIProvider() })` in TypeScript. Defaults to OpenAI if omitted.
5. **Correct provider imports** — `composio_<provider>` for Python, `@composio/<provider>` for TypeScript. For OpenAI Agents SDK use `composio_openai_agents` / `@composio/openai-agents`.
6. **Finding toolkit and tool slugs** — browse the Toolkits catalog at https://docs.composio.dev/toolkits (each toolkit page lists tool slugs and versions), or search by task with the CLI: `composio search "<what you want to do>"`.

---

# Calling the REST API directly

## REST API version

The current REST API version is **v3.1**, served at `https://backend.composio.dev/api/v3.1`. Prefer it for new code and new examples.

`https://backend.composio.dev/api/v3` is the previous version. It is frozen with pinned tool-version defaults and remains supported — existing v3 integrations keep working and do not need to migrate.

## Tool-endpoint version defaults on v3.1

On v3.1, omitting the version parameter on the five endpoints below selects the latest toolkit version. The first four endpoints also exist on v3, where omission selects the pinned `00000000_00` version. `POST /tools/scopes/required` is v3.1-only.

| Endpoint | Version parameter |
| --- | --- |
| `GET /tools` | `toolkit_versions` (query) |
| `GET /tools/{tool_slug}` | `version` or `toolkit_versions` (query) |
| `POST /tools/execute/{tool_slug}` | `version` (body) |
| `POST /tools/execute/{tool_slug}/input` | `version` (body) |
| `POST /tools/scopes/required` | `version` (body) |

A v3.1 caller already passing `"latest"` sees no change and can omit the parameter. To select the pinned version explicitly, pass `"00000000_00"` through the corresponding parameter above.

This version-default change is limited to the five endpoints above.


---

## Terminology Migration (old → current)

If you encounter these terms in error messages, old documentation, or user prompts, translate them to the current equivalents. **Do not use the old terms in generated code or explanations.**

| Old term (v1/v2) | Current term (v3) | In code |
|---|---|---|
| entity ID | user ID | `user_id` parameter |
| actions | tools | e.g., `GITHUB_CREATE_ISSUE` is a *tool* |
| apps / appType | toolkits | e.g., `github` is a *toolkit* |
| integration / integration ID | auth config / auth config ID | `auth_config_id` parameter |
| connection | connected account | `connected_accounts` namespace |
| ComposioToolSet / OpenAIToolSet | `Composio` class with a provider | `Composio(provider=...)` |
| toolset | provider | e.g., `OpenAIProvider` |

If a user says "entity ID", they mean `user_id`. If they say "integration", they mean "auth config". Always respond using the current terminology.

