Generic Elixir client for the public Factorial HR REST API.
This package intentionally stays below any product/domain mapping layer. It knows how to authenticate, build versioned resource URLs, follow Factorial's cursor pagination and call common HR endpoints, returning Factorial payloads as maps.
Quick start
opts = [
api_key: System.fetch_env!("FACTORIAL_API_KEY"),
api_version: "2026-04-01"
]
{:ok, employees} = FactorialHR.list_employees([only_active: true], opts)The client also accepts bearer access tokens for applications that implement their own OAuth flow.
Telemetry
When :telemetry is available, requests emit:
[:factorial_hr, :request, :start][:factorial_hr, :request, :stop][:factorial_hr, :request, :exception]
Request metadata includes the HTTP method, resource path and resolved URL.
Summary
Functions
Fetches every page from a cursor-paginated Factorial collection.
Creates several shifts in Factorial shift management.
Bulk-deletes shifts.
Creates one shift in Factorial shift management.
Executes a DELETE request against a versioned Factorial resource path.
Deletes one shift by Factorial shift-management ID.
Executes a GET request against a versioned Factorial resource path.
Lists Factorial attendance shifts for a date range.
Lists Factorial contract compensations.
Lists Factorial contract versions.
Lists Factorial employees.
Lists Factorial workplace locations.
Lists Factorial shift-management shifts.
Lists unique employee IDs from the Factorial teams endpoint.
Lists Factorial teams.
Lists Factorial work areas.
Executes a POST request against a versioned Factorial resource path.
Types
@type client_opts() :: keyword() | map() | FactorialHR.Config.t()
@type response_result() :: {:ok, Req.Response.t()} | {:error, FactorialHR.Error.t()}
@type result() :: {:ok, term()} | {:error, FactorialHR.Error.t()}
Functions
@spec all(String.t(), params(), String.t() | nil, client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Fetches every page from a cursor-paginated Factorial collection.
@spec bulk_create_shifts([map()], client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Creates several shifts in Factorial shift management.
@spec bulk_delete_shifts([integer()] | params(), client_opts()) :: :ok | {:error, FactorialHR.Error.t()}
Bulk-deletes shifts.
Pass a list of IDs or a map/keyword list matching Factorial's bulk delete
filters. author_id is read from params first, then from client config.
Empty ID lists are rejected before making an API request.
@spec create_shift(map(), client_opts()) :: {:ok, map()} | {:error, FactorialHR.Error.t()}
Creates one shift in Factorial shift management.
company_id can be passed per shift or configured once in the client opts.
FactorialHR.create_shift(
%{
employee_id: 42,
start_at: "2026-06-01T08:00:00Z",
end_at: "2026-06-01T16:00:00Z",
location_id: 7,
work_area_id: 8
},
Keyword.put(opts, :company_id, 123)
)
@spec delete(String.t(), client_opts()) :: response_result()
Executes a DELETE request against a versioned Factorial resource path.
@spec delete_shift(integer() | String.t(), client_opts()) :: :ok | {:error, FactorialHR.Error.t()}
Deletes one shift by Factorial shift-management ID.
A 404 is treated as success to make delete operations idempotent.
@spec get(String.t(), params(), client_opts()) :: response_result()
Executes a GET request against a versioned Factorial resource path.
Pass a resource path such as "/employees/employees". The client adds the
/api/:version/resources prefix from the configured API version.
Returns the raw %Req.Response{} for successful 2xx responses and a
structured %FactorialHR.Error{} for non-2xx HTTP responses or request
failures.
@spec list_attendance_shifts( Date.t() | String.t(), Date.t() | String.t(), params(), client_opts() ) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial attendance shifts for a date range.
@spec list_compensations(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial contract compensations.
@spec list_contract_versions(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial contract versions.
@spec list_employees(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial employees.
@spec list_locations(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial workplace locations.
@spec list_shifts(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial shift-management shifts.
Recognized convenience params include :employee_ids, :location_ids,
:start_at, :end_at, :only_published, :only_states and
:split_overnight_shifts. Other params are passed through unchanged.
FactorialHR.list_shifts(
[
employee_ids: [123, 456],
start_at: "2026-06-01",
end_at: "2026-06-30",
only_states: ["published"]
],
opts
)
@spec list_team_employee_ids(client_opts()) :: {:ok, [integer()]} | {:error, FactorialHR.Error.t()}
Lists unique employee IDs from the Factorial teams endpoint.
Factorial team payloads can expose employee_ids or expanded employees.
This helper is generic and performs no tenant-specific filtering.
@spec list_teams(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial teams.
@spec list_work_areas(params(), client_opts()) :: {:ok, [map()]} | {:error, FactorialHR.Error.t()}
Lists Factorial work areas.
@spec post(String.t(), map(), client_opts()) :: response_result()
Executes a POST request against a versioned Factorial resource path.