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

# SDK overview

> engini (Python) and @engini/sdk (TypeScript) - one surface, two languages.

The Python and TypeScript SDKs expose an identical surface by design - same resources, same semantics, mirrored naming (snake\_case in Python, camelCase in TypeScript).

## Install

<CodeGroup>
  ```bash Python theme={null}
  pip install engini              # Python >= 3.9
  pip install 'engini[cli]'       # + the engini CLI
  ```

  ```bash TypeScript theme={null}
  npm install @engini/sdk         # ESM, ships type declarations
  npm install -g @engini/cli      # the engini CLI (separate package)
  ```
</CodeGroup>

## Authentication

<CodeGroup>
  ```python Python theme={null}
  from engini import Engini

  client = Engini()                      # reads ENGINI_API_KEY (preferred) or ENGINI_API_TOKEN
  client = Engini(api_key="eng_...")     # explicit API key -> x-api-key header
  client = Engini(token="...")           # explicit PAT     -> Authorization: Bearer
  ```

  ```typescript TypeScript theme={null}
  import { Engini } from "@engini/sdk";

  const client = new Engini();                     // reads ENGINI_API_KEY (preferred) or ENGINI_API_TOKEN
  const client2 = new Engini({ apiKey: "eng_..." });
  const client3 = new Engini({ token: "..." });
  ```
</CodeGroup>

`api_key`/`token`/`auth` are mutually exclusive. Verify a credential with `client.auth.whoami()`. How the two credential types differ: [Authentication](/concepts/authentication).

Other constructor options: `base_url`/`baseUrl` (defaults to `https://api.engini.io`), `provider` (LLM adapter, defaults to OpenAI), `verify` (TLS control for private CAs / staging).

## The resources

| Resource              | What it does                                                                      |
| --------------------- | --------------------------------------------------------------------------------- |
| `client.tools`        | Discover tools (`get`), read one schema (`get_one`/`getOne`), execute (`execute`) |
| `client.connections`  | List/create/delete connections, the OAuth flow, object selection, defaults        |
| `client.toolsets`     | Server-persisted toolset CRUD                                                     |
| `client.applications` | Browse the application catalog (`list`, `get`)                                    |
| `client.auth`         | `whoami()` - identity behind the credential                                       |
| `client.toolset(...)` | Build a [`Toolset`](/sdk/toolsets) - the LLM-facing tool belt                     |

## Execute a tool

<CodeGroup>
  ```python Python theme={null}
  tools = client.tools.get(applications=["salesforce"], search="accounts", limit=5)

  result = client.tools.execute(
      "salesforce_getrecords", {"sobject": "Account"}, connection_id=conn_id
  )
  print(result.output, result.history_id)
  ```

  ```typescript TypeScript theme={null}
  const tools = await client.tools.get({ applications: ["salesforce"], search: "accounts", limit: 5 });

  const result = await client.tools.execute(
    "salesforce_getrecords",
    { sobject: "Account" },
    { connectionId },
  );
  console.log(result.output, result.historyId);
  ```
</CodeGroup>

## Errors, pagination & rate limits

* Every failure raises a **typed error** from one hierarchy (`EnginiAuthError`, `EnginiRateLimitError`, `EnginiToolExecutionError`...) - full tree and handling patterns: [Errors & pagination](/sdk/errors-and-pagination).
* **You never page manually**: list methods auto-paginate and return complete arrays.
* The SDK does **not** retry automatically - on `EnginiRateLimitError`, back off per the API's [rate-limit rules](/concepts/pagination-and-errors).

## Python vs TypeScript in one minute

* Python is fully **synchronous**; TypeScript is fully **async** (`await` everything).
* Execute's arguments param: `arguments` (Python) vs `args` (TS); options are keyword-only (Python) vs a trailing options object (TS).
* Providers import from the root in TS (`import { AnthropicProvider } from "@engini/sdk"`) but from submodules in Python (`from engini.providers.anthropic import AnthropicProvider`).
* List methods auto-paginate in both - you always get the full array.
* Neither SDK retries automatically - handle `EnginiRateLimitError`/`EnginiServerError` yourself if you need retries.
