Official auto-generated SDKs for the Factorial API, available for TypeScript, Python and Ruby.
The SDKs are generated from the OpenAPI spec and wrapped with a handwritten or generated client layer providing clean resource access, auth handling and cursor pagination helpers.
npm install @factorialco/api-clientimport { FactorialClient } from "@factorialco/api-client";
const client = new FactorialClient({ apiKey: process.env.FACTORIAL_API_KEY });
const page = await client.employees.employees.list();
for await (const emp of client.employees.employees.paginate({ maxItems: 50 })) {
console.log(emp.full_name);
}pip install factorial-api-clientfrom factorial_api_client import FactorialClient
client = FactorialClient(api_key="YOUR_KEY")
result = client.employees.employee.list()
for emp in client.employees.employee.paginate(max_items=50):
print(emp.full_name)gem install factorial_apirequire "factorial_api"
api = F::Api.new(api_key: "YOUR_KEY")
# only_active, only_managers (required query params become positional args)
page = api.employees_employee.employees_employees_get(true, false)
F::Api.paginate(max_items: 50) { |p| api.employees_employee.employees_employees_get(true, false, query_params: p) }
.each { |emp| puts emp.full_name }The TypeScript and Python SDKs use standard semver (MAJOR.MINOR.PATCH), independent of the Factorial API version date.
| SDK version | Factorial API version |
|---|---|
1.x.y |
2026-04-01 |
2.x.y |
2026-07-01 |
Factorial releases new API versions quarterly (Jan/Apr/Jul/Oct).
Releases are automated with release-please.
Land Conventional Commits on main, then
merge the Release PR it opens — that bumps the version, tags the commit, creates
the GitHub Release, and publishes to npm / PyPI. You never tag or publish by hand.
See RELEASING.md for the full flow.
When opening a PR, two things decide the release:
- PRs are squash-merged, so the PR title must be a Conventional Commit
(
feat:→ minor,fix:→ patch,feat!:/BREAKING CHANGE:→ major). - Which package bumps is decided by file path: changes under
typescript/bump the npm package, underpython/the PyPI package. For a change spanning both SDKs, use a barefeat:/fix:with no scope so both bump together.
The Ruby SDK follows the same semver +
version_map.jsonmodel but is not wired into release-please yet: its version is computed byruby/scripts/generate_sdk.rbfor now — see ruby/DEVELOPMENT.md.
The release.ts / release.py scripts remain for regenerating the SDK from a
new OpenAPI spec; see the per-SDK READMEs: TypeScript · Python
Regenerating for a new dated API version is a repeatable runbook, captured as the
release-sdk agent skill (.agents/skills/release-sdk/) for coding agents to follow.
Generate SDK from latest spec
cd typescript
npm run generateFetches the OpenAPI spec from https://api.factorialhr.com/oas/?version=<date> and regenerates all src/generated/*.gen.ts files. Override the URL with:
OPENAPI_SPEC_URL=./local-spec.json npm run generateTest against the live API
FACTORIAL_API_KEY=your_key npm run test:api
# or with OAuth token:
FACTORIAL_TOKEN=your_token npm run test:apiRelease a new version
npm run release # patch bump (default)
npm run release -- --bump minor # minor bump
npm run release -- --bump major # major bump
npm run release:dry-run # preview only — no writes, no publishThe release script:
- Prompts for the API version date (
yyyy-mm-dd). - Fetches the spec from
https://api.factorialhr.com/oas/?version=<date>. - Regenerates
src/generated/(stage 1) andsrc/sdk.ts(stage 2). - Bumps the SDK semver (
--bump major|minor|patch, defaultpatch). - Builds the package, then asks whether to publish to npm.
All SDKs support:
- API key — via
apiKey:/api_key=(sent asx-api-keyheader) - OAuth2 bearer token — via
token:/token=(sent asAuthorization: Bearer)
If you don't pass credentials (or a base URL) explicitly, the client reads them from the environment. Explicit arguments always take precedence.
| Variable | Maps to | Sent as |
|---|---|---|
FACTORIAL_API_KEY |
API key | x-api-key header |
FACTORIAL_TOKEN |
OAuth2 token | Authorization: Bearer |
FACTORIAL_BASE_URL |
Base URL | — (defaults to https://api.factorialhr.com) |
// TypeScript — picks up FACTORIAL_API_KEY / FACTORIAL_TOKEN / FACTORIAL_BASE_URL
const client = new FactorialClient();# Python — same
client = FactorialClient()# Ruby — same
api = F::Api.newThe TypeScript client reads
process.env, so env-var fallback applies in Node-like runtimes; in the browser, pass credentials explicitly.
All SDKs fail loudly on non-2xx responses (bad/expired token, wrong base URL, server errors) instead of silently returning empty data:
- TypeScript throws — wrap calls in
try/catch. - Python raises
factorial_api_client.generated.errors.UnexpectedStatus(with.status_codeand.content). - Ruby raises
F::Api::ApiError(with.codeand.response_body).