> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developer.vitablehealth.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developer.vitablehealth.com/_mcp/server.

# Migrating to SDK v1.0

> What changed in the v1.0 release of the Vitable Connect SDKs, and how to upgrade from a 0.x version.

The v1.0 release of the Vitable Connect SDKs is a new generation of our client
libraries, rebuilt on a new SDK pipeline. **The REST API itself is unchanged** —
same endpoints, same request and response shapes on the wire, same
authentication — but the generated client code has a new internal architecture,
so upgrading from a 0.x SDK requires some code changes.

Package names are unchanged on every registry, so the upgrade is a normal
version bump:

**`TypeScript`**

```bash title="TypeScript"
npm install @vitable-inc/vitable-connect@^1.0.0
```

**`Python`**

```bash title="Python"
pip install --upgrade "vitable_connect>=1.0.0"
```

**`Ruby`**

```bash title="Ruby"
# Gemfile
gem "vitable-connect", "~> 1.0"
```

> **Note**
>
> Every endpoint page in the [API Reference](/api) shows install and usage
> snippets generated directly from the v1 SDKs. When in doubt about exact
> syntax for a specific call, the reference is the source of truth.

## What stays the same

* **Authentication.** The client still reads your API key from the
  `VITABLE_CONNECT_API_KEY` environment variable by default, and still accepts
  it explicitly via the same constructor option (`apiKey` / `api_key:`).
* **Python and Ruby entry points.** `from vitable_connect import
  VitableConnect` and `VitableConnect::Client.new(...)` work as before, and
  Python's async client is still `AsyncVitableConnect`.
* **Resource layout.** Calls are still grouped by resource
  (`client.auth`, `client.employees`, `client.employers`, ...), with the same
  method names in Python and Ruby.
* **Typed responses.** Responses remain fully typed objects in every language.

## What changed

### TypeScript

The two changes most likely to touch your code are the client import and
property casing.

**Client import and construction.** The package's default export has been
replaced with a named client class:

```ts
// Before (0.x)
import VitableConnect from "@vitable-inc/vitable-connect";
const client = new VitableConnect({
  apiKey: process.env["VITABLE_CONNECT_API_KEY"],
});

// After (1.x)
import { VitableConnectClient } from "@vitable-inc/vitable-connect";
const client = new VitableConnectClient({
  apiKey: process.env["VITABLE_CONNECT_API_KEY"],
});
```

**Property casing is now camelCase.** In 0.x, request parameters and response
fields mirrored the wire format's snake_case. In 1.x they are idiomatic
camelCase, converted to and from the wire format for you:

```ts
// Before (0.x)
const response = await client.auth.issueAccessToken({
  grant_type: "client_credentials",
});
console.log(response.access_token);

// After (1.x)
const response = await client.auth.issueAccessToken({
  grantType: "client_credentials",
});
console.log(response.accessToken);
```

**Pagination** is still an async-iterable page — `for await` loops carry over
with at most a casing change on the item fields:

```ts
const enrollments = await client.employees.listEnrollments("empl_abc123def456");
for await (const enrollment of enrollments) {
  console.log(enrollment.id);
}
```

**Errors.** The per-status error classes (`BadRequestError`,
`AuthenticationError`, `RateLimitError`, ...) are replaced by a single error
hierarchy rooted at `VitableConnectError`, which carries the HTTP status code
and the response body. Branch on `statusCode` instead of the class:

```ts
import { VitableConnectError } from "@vitable-inc/vitable-connect";

try {
  await client.employees.get("empl_abc123def456");
} catch (err) {
  if (err instanceof VitableConnectError) {
    console.error(err.statusCode, err.message, err.body);
  }
}
```

**Retries and timeouts** are configured per request rather than only on the
client. Every method accepts a final options argument:

```ts
await client.auth.issueAccessToken(
  { grantType: "client_credentials" },
  { maxRetries: 0, timeoutInSeconds: 20 },
);
```

### Python

Python is close to a drop-in upgrade: imports, client class names, method
names, and snake_case parameters are unchanged.

```python
from vitable_connect import VitableConnect

client = VitableConnect()  # reads VITABLE_CONNECT_API_KEY

response = client.auth.issue_access_token(grant_type="client_credentials")
print(response.access_token)
```

The changes to review:

* **Errors.** The per-status classes are replaced by a single `ApiError` base
  carrying `status_code` and `body`. Replace `except NotFoundError:` style
  handlers with a branch on the status code:

  ```python
  from vitable_connect.core.api_error import ApiError

  try:
      client.employees.get("empl_abc123def456")
  except ApiError as err:
      if err.status_code == 404:
          ...  # not found
      else:
          raise
  ```

* **Pagination** still iterates transparently across pages:

  ```python
  for enrollment in client.employees.list_enrollments(
      employee_id="empl_abc123def456",
  ):
      print(enrollment.id)
  ```

* **Retries and timeouts** can now also be set per request via
  `request_options`, in addition to client-wide configuration.

### Ruby

The client entry point and method calls are unchanged:

```ruby
client = VitableConnect::Client.new(api_key: ENV["VITABLE_CONNECT_API_KEY"])

response = client.auth.issue_access_token(grant_type: "client_credentials")
puts response.access_token
```

The changes to review:

* **Pagination.** `auto_paging_each` is replaced by standard iteration — list
  calls return an enumerable that fetches subsequent pages automatically:

  ```ruby
  client.employees.list_enrollments(employee_id: "empl_abc123def456").each do |enrollment|
    puts enrollment.id
  end
  ```

* **Errors.** The `VitableConnect::Errors::*` per-status classes are replaced
  by a single API error rooted in the `VitableConnect` module carrying the
  HTTP status code and response body. Rescue the base error and branch on the
  status code.

## Staying on 0.x

The 0.x packages remain on the registries and keep working against the API,
but they no longer receive updates — new endpoints and fields will only appear
in 1.x. If you are not ready to migrate, pin your dependency to your current
0.x version and plan the upgrade.

## Questions

If you hit a migration issue not covered here, contact your Vitable
integration engineer or email [dev@vitablehealth.com](mailto:dev@vitablehealth.com).