factorial-api-sdks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Factorial API SDKs

Factorial API SDK集合

Official SDKs that wrap the Factorial public API with a domain-namespaced client, pagination helpers, and clean auth. This skill teaches an agent how to use them and how to work with Factorial webhooks. Generated reference data lives in
reference/
(see References).
  • TypeScript:
    @factorialco/api-client
    (npm)
  • Python:
    factorial-api-client
    (PyPI)
  • Ruby:
    factorial_api
    (RubyGems)
官方SDK集合,通过领域命名空间客户端、分页辅助工具和简洁的身份验证封装了Factorial公开API。本技能将指导Agent如何使用这些SDK以及如何处理Factorial webhook。生成的参考数据存放在
reference/
目录中(参见参考资料)。
  • TypeScript
    @factorialco/api-client
    (npm)
  • Python
    factorial-api-client
    (PyPI)
  • Ruby
    factorial_api
    (RubyGems)

Install

安装

bash
npm install @factorialco/api-client     # TypeScript
pip install factorial-api-client          # Python
gem install factorial_api                 # Ruby
bash
npm install @factorialco/api-client     # TypeScript
pip install factorial-api-client          # Python
gem install factorial_api                 # Ruby

Authentication

身份验证

Provide either an API key or an OAuth token (or both):
OptionHeader sent
apiKey
x-api-key: <value>
token
Authorization: Bearer <value>
The Factorial API key is JWT-formatted but is sent as
x-api-key
, not as a bearer token.
Credentials can be passed explicitly or read from the environment (
FACTORIAL_API_KEY
,
FACTORIAL_TOKEN
, optional
FACTORIAL_BASE_URL
).
ts
import { FactorialClient } from "@factorialco/api-client";
const client = new FactorialClient({ apiKey: process.env.FACTORIAL_API_KEY });
python
from factorial_api_client import FactorialClient
client = FactorialClient(api_key="YOUR_KEY")   # or token="...", or from env
ruby
require "factorial_api"
api = F::Api.new(api_key: ENV["FACTORIAL_API_KEY"])   # or token:, or from env
提供API密钥OAuth令牌(也可同时提供):
选项发送的请求头
apiKey
x-api-key: <value>
token
Authorization: Bearer <value>
Factorial API密钥采用JWT格式,但需通过
x-api-key
请求头发送,而非作为Bearer令牌。
凭据可显式传递,也可从环境变量中读取(
FACTORIAL_API_KEY
FACTORIAL_TOKEN
,可选
FACTORIAL_BASE_URL
)。
ts
import { FactorialClient } from "@factorialco/api-client";
const client = new FactorialClient({ apiKey: process.env.FACTORIAL_API_KEY });
python
from factorial_api_client import FactorialClient
client = FactorialClient(api_key="YOUR_KEY")   # or token="...", or from env
ruby
require "factorial_api"
api = F::Api.new(api_key: ENV["FACTORIAL_API_KEY"])   # or token:, or from env

Calling endpoints

调用端点

The client is organized as
client.<namespace>.<resource>.<method>
. Namespaces and resources mirror the REST path
/api/<version>/resources/<namespace>/<resource>
.
Method naming is deterministic:
HTTP / shapeSDK method
GET
collection
list()
/
paginate()
/
all()
GET
by id
get(id)
POST
collection
create(body)
PUT
/
PATCH
by id
update(id, body)
DELETE
by id
delete(id)
Custom action (e.g.
apply
)
camelCased action, e.g.
apply()
ts
const { data } = await client.employees.employees.list();
const created = await client.apiPublic.webhookSubscriptions.create({ /* body */ });
python
employees = client.employees.employee.list()
sub = client.api_public.webhook_subscription.create(body={...})
Ruby differs: it exposes one accessor per resource (
api.employees_employee
) whose methods are the spec operationIds; required params are positional and optional query params go in a
query_params:
hash.
ruby
employees = api.employees_employee.employees_employees_get(true, false).data
To discover the exact namespace/resource/method for any endpoint, consult
reference/sdk-methods.md
(every endpoint with its TS and Ruby calls, grouped) or the online API reference.
客户端采用
client.<命名空间>.<资源>.<方法>
的组织形式。命名空间和资源与REST路径
/api/<版本>/resources/<命名空间>/<资源>
一一对应。
方法命名遵循固定规则:
HTTP方法/请求类型SDK方法
GET
集合资源
list()
/
paginate()
/
all()
GET
单个资源(按ID)
get(id)
POST
创建集合资源
create(body)
PUT
/
PATCH
更新单个资源
update(id, body)
DELETE
删除单个资源
delete(id)
自定义操作(如
apply
驼峰式命名的操作,例如
apply()
ts
const { data } = await client.employees.employees.list();
const created = await client.apiPublic.webhookSubscriptions.create({ /* body */ });
python
employees = client.employees.employee.list()
sub = client.api_public.webhook_subscription.create(body={...})
Ruby有所不同:它为每个资源暴露一个访问器(如
api.employees_employee
),其方法为规范的operationId;必填参数为位置参数,可选查询参数需放在
query_params:
哈希中。
ruby
employees = api.employees_employee.employees_employees_get(true, false).data
如需查询任意端点对应的命名空间/资源/方法,请查阅
reference/sdk-methods.md
(所有端点及其TS和Ruby调用示例,按组划分)或在线API参考文档

Pagination

分页

List endpoints return
{ data: T[], meta: { end_cursor?, has_next_page, ... } }
.
  • list()
    — one raw page
  • paginate()
    — async iterator (TS) / sync or async generator (Python)
  • all()
    (TS) /
    collect_all()
    (Python) — fetch every page into one array/list
  • Ruby:
    F::Api.paginate { |page| ... }
    wraps any list call in a lazy Enumerator
ts
for await (const emp of client.employees.employees.paginate()) { /* ... */ }
const everyone = await client.employees.employees.all({ maxItems: 500 });
python
for emp in client.employees.employee.paginate(max_items=50): ...
everyone = client.employees.employee.all()
列表端点返回
{ data: T[], meta: { end_cursor?, has_next_page, ... } }
格式的数据。
  • list()
    — 返回原始单页数据
  • paginate()
    — 异步迭代器(TS)/ 同步或异步生成器(Python)
  • all()
    (TS)/
    collect_all()
    (Python) — 获取所有页面数据并合并为一个数组/列表
  • Ruby:
    F::Api.paginate { |page| ... }
    将任意列表调用包装为惰性枚举器
ts
for await (const emp of client.employees.employees.paginate()) { /* ... */ }
const everyone = await client.employees.employees.all({ maxItems: 500 });
python
for emp in client.employees.employee.paginate(max_items=50): ...
everyone = client.employees.employee.all()

High-volume retrieval

高容量数据检索

Pages are capped at 100 items — a server-side hard max, not a default (see the pagination docs). Passing a larger
limit
has no effect. Cursor pagination is sequential (page N+1 needs page N's
end_cursor
), so
all()
on a big dataset (e.g. a full company-month of
attendance/worked_times
) means dozens of sequential requests. To keep request counts and latency sane:
  • Filter first. Use the endpoint's query params (date ranges,
    ids
    ,
    employee_ids
    , …) instead of pulling everything and filtering locally.
  • Sync incrementally. Where an endpoint supports
    updated_at
    -style filters, fetch only what changed since your last run and cache locally — don't re-pull the full dataset per report.
  • Shard big pulls. Split one large query into filtered sub-queries (by date window or id chunks) and run those concurrently — each sub-query still paginates sequentially, but wall-clock time drops. Total request count is unchanged, so watch rate limits.
  • Cap defensively. Pass
    max_items
    /
    maxItems
    so a bug or unexpected data volume can't turn into an unbounded crawl.
There is no server-side aggregation endpoint; totals (e.g. hours per employee per period) must be computed client-side from the raw records.
每页最多返回100条数据——这是服务器端的硬限制,而非默认值(参见分页文档)。传入更大的
limit
参数不会生效。游标分页是顺序执行的(获取第N+1页需要第N页的
end_cursor
),因此对大型数据集(例如某公司整月的
attendance/worked_times
数据)调用
all()
会触发数十次顺序请求。为了控制请求数量和延迟,请遵循以下建议:
  • 先过滤。使用端点的查询参数(日期范围、
    ids
    employee_ids
    等)进行过滤,而非拉取全部数据后在本地过滤。
  • 增量同步。如果端点支持
    updated_at
    类过滤条件,仅拉取自上次运行以来变更的数据并在本地缓存——不要每次生成报告时都重新拉取完整数据集。
  • 拆分大查询。将一个大型查询拆分为多个带过滤条件的子查询(按时间窗口或ID分段)并并发执行——每个子查询仍需顺序分页,但整体耗时会大幅降低。总请求数量不变,因此需注意速率限制。
  • 合理设置上限。传入
    max_items
    /
    maxItems
    参数,避免因bug或意外的数据量导致无限制的爬取。
服务器端没有聚合端点;统计数据(例如每个员工每个时段的工时)必须从原始记录中在客户端计算得出。

Errors

错误处理

The client throws on any non-2xx response (bad/expired token, wrong base URL, server errors) instead of silently returning empty data. Wrap calls in try/catch (TS) or try/except (Python).
客户端会在任何非2xx响应(无效/过期令牌、错误的基础URL、服务器错误)时抛出异常,而非静默返回空数据。请将调用代码包裹在try/catch(TypeScript)或try/except(Python)块中。

API versioning

API版本控制

The SDK targets a specific Factorial API date version (e.g.
2026-04-01
), pinned by the SDK's major version. Newer API versions ship as new SDK majors.
SDK针对特定的Factorial API日期版本(例如
2026-04-01
),该版本由SDK的主版本号固定。更新的API版本会作为新的SDK主版本发布。

Webhooks

Webhook

Webhooks are HTTP POSTs Factorial sends to your
target_url
when an event happens.
How delivery works
  • You create a webhook subscription for a
    subscription_type
    (e.g.
    ats/application/create
    ), pointing at a
    target_url
    , with your
    company_id
    .
  • When the event fires, Factorial sends a
    POST
    to
    target_url
    . The payload is the resource object at the top level — it is not wrapped in a
    { type, data }
    envelope. Use a distinct URL per event if you need to tell them apart easily.
  • If you set a
    challenge
    when subscribing, Factorial echoes it back in the
    x-factorial-wh-challenge
    request header so you can verify the source.
  • Optional author headers
    x-factorial-author-id
    /
    x-factorial-author-type
    (
    employee
    or
    company
    ) identify who triggered the event, when safe to expose.
  • Retry policy: up to 20 retries over 48h; after that the subscription is disabled and you are emailed. Re-enable with a
    PUT { enabled: true }
    .
Manage subscriptions via the SDK
ts
await client.apiPublic.webhookSubscriptions.create({
  subscription_type: "ats/application/create",
  target_url: "https://example.com/webhooks/factorial",
  challenge: "a-secret-you-choose",
  company_id: 55,
});
python
client.api_public.webhook_subscription.create(body={
    "subscription_type": "ats/application/create",
    "target_url": "https://example.com/webhooks/factorial",
    "challenge": "a-secret-you-choose",
    "company_id": 55,
})
Type the handler payload with the exported webhook types:
ts
import type { AtsApplicationCreateWebhook, WebhookPayloadMap, WebhookSubscriptionType }
  from "@factorialco/api-client";

// Direct alias
function onApplicationCreated(payload: AtsApplicationCreateWebhook) { /* ... */ }

// Typed dispatch keyed on the runtime subscription_type
function handle<T extends WebhookSubscriptionType>(type: T, payload: WebhookPayloadMap[T]) { /* ... */ }
python
from factorial_api_client import AtsApplicationCreateWebhook, WEBHOOK_PAYLOAD_TYPES

def on_application_created(payload: AtsApplicationCreateWebhook) -> None: ...
Webhook是Factorial在事件发生时发送到您指定
target_url
的HTTP POST请求。

Runtime lookup of the model class for a subscription_type

交付机制

model_cls = WEBHOOK_PAYLOAD_TYPES["ats/application/create"]

The full list of events, their `subscription_type`, and payload fields is in
`reference/webhooks.md`.
  • 您需要为特定
    subscription_type
    (例如
    ats/application/create
    )创建一个webhook订阅,指定
    target_url
    和您的
    company_id
  • 当事件触发时,Factorial会向
    target_url
    发送一个
    POST
    请求。负载为顶层的资源对象——不会被包裹在
    { type, data }
    格式的信封中。如果您需要轻松区分不同事件,请为每个事件使用独立的URL。
  • 如果您在订阅时设置了
    challenge
    参数,Factorial会在
    x-factorial-wh-challenge
    请求头中返回该参数,以便您验证请求来源。
  • 可选的请求头
    x-factorial-author-id
    /
    x-factorial-author-type
    employee
    company
    )会标识触发事件的对象(在安全可暴露的前提下)。
  • 重试策略:最多重试20次,持续48小时;超过次数后订阅将被禁用,并向您发送邮件通知。可通过
    PUT { enabled: true }
    请求重新启用订阅。

References

通过SDK管理订阅

Generated, SDK-specific lookup tables (consult these for exact names/shapes):
  • reference/webhooks.md
    — every webhook event, its
    subscription_type
    , and payload fields.
  • reference/sdk-methods.md
    — every REST endpoint grouped by namespace/resource, with the SDK call.
For prose guides (OAuth flows, API keys, versioning, webhook policies, etc.), use the live docs — always current, not vendored here:
ts
await client.apiPublic.webhookSubscriptions.create({
  subscription_type: "ats/application/create",
  target_url: "https://example.com/webhooks/factorial",
  challenge: "a-secret-you-choose",
  company_id: 55,
});
python
client.api_public.webhook_subscription.create(body={
    "subscription_type": "ats/application/create",
    "target_url": "https://example.com/webhooks/factorial",
    "challenge": "a-secret-you-choose",
    "company_id": 55,
})

为处理程序负载添加类型定义

使用导出的webhook类型:
ts
import type { AtsApplicationCreateWebhook, WebhookPayloadMap, WebhookSubscriptionType }
  from "@factorialco/api-client";

// 直接别名
function onApplicationCreated(payload: AtsApplicationCreateWebhook) { /* ... */ }

// 根据运行时subscription_type进行类型化分发
function handle<T extends WebhookSubscriptionType>(type: T, payload: WebhookPayloadMap[T]) { /* ... */ }
python
from factorial_api_client import AtsApplicationCreateWebhook, WEBHOOK_PAYLOAD_TYPES

def on_application_created(payload: AtsApplicationCreateWebhook) -> None: ...

根据subscription_type在运行时查找模型类

model_cls = WEBHOOK_PAYLOAD_TYPES["ats/application/create"]

完整的事件列表、对应的`subscription_type`及负载字段可在`reference/webhooks.md`中查看。

参考资料

生成的SDK专属查询表(如需精确名称/格式,请查阅这些文档):
  • reference/webhooks.md
    — 所有webhook事件、对应的
    subscription_type
    及负载字段。
  • reference/sdk-methods.md
    — 所有REST端点按命名空间/资源分组,并附带SDK调用示例。
如需详细指南(OAuth流程、API密钥、版本控制、webhook策略等),请使用在线文档——始终保持最新,而非本地存储的版本: