Migrating to SDK v1.0

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:

npm install @vitable-inc/vitable-connect@^1.0.0

Every endpoint page in the API Reference 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:

// 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:

// 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:

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:

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:

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.

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:

    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:

    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:

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:

    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.