# Humaans

[![Build Status](https://github.com/sgerrand/ex_humaans/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sgerrand/ex_humaans/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/sgerrand/ex_humaans/badge.svg?branch=main)](https://coveralls.io/github/sgerrand/ex_humaans?branch=main)
[![Hex Version](https://img.shields.io/hexpm/v/humaans.svg)](https://hex.pm/packages/humaans)
[![Hex Docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](https://hexdocs.pm/humaans/)

An Elixir client for the [Humaans API][humaans-api-docs].

## Installation

The package can be installed by adding `humaans` to your list of dependencies in
`mix.exs`:

<!-- x-release-please-start-version -->
```elixir
def deps do
  [
    {:humaans, "~> 0.6.0"}
  ]
end
```
<!-- x-release-please-end -->

## Usage

To use this client with the Humaans API, you'll need to generate an API access token in the Humaans application.

### Client-based approach

The recommended way to use this library is to instantiate a client first:

```elixir
# Create a client with your access token
client = Humaans.new(access_token: "YOUR_ACCESS_TOKEN")

# Make API requests passing the client as the first argument
{:ok, people} = Humaans.People.list(client)
{:ok, person} = Humaans.People.retrieve(client, "person_id")
{:ok, company} = Humaans.Companies.retrieve(client, "company_id")
```

This approach allows you to create multiple clients with different access tokens and use them independently.

### Tuning the HTTP client

Pass `:req_options` to `Humaans.new/1` to customise the underlying [Req][req] client (timeouts, retries, plugins, etc.):

```elixir
client =
  Humaans.new(
    access_token: "YOUR_ACCESS_TOKEN",
    req_options: [connect_options: [timeout: 30_000], retry: :transient]
  )
```

For deeper customisation, implement `Humaans.HTTPClient.Behaviour` and pass the module via `:http_client`.

[req]: https://hexdocs.pm/req/

### Module access helpers

The library provides convenience functions to access the different resource modules:

```elixir
client = Humaans.new(access_token: "YOUR_ACCESS_TOKEN")

# Use the module access helpers
{:ok, people} = Humaans.people().list(client)
{:ok, accounts} = Humaans.bank_accounts().list(client)
{:ok, companies} = Humaans.companies().list(client)
```

### Rate-limit retries

The default HTTP client retries transient failures (status 408, 429, 500, 502, 503, 504) up to 3 times with exponential backoff, honouring the `Retry-After` header. To opt out, pass `req_options: [retry: false]` to `Humaans.new/1`.

### Snake_case request bodies

You can write request bodies in idiomatic snake_case — `Humaans.Client` converts top-level keys to camelCase before sending them to the API. Already-camelCase keys keep their casing, so existing code that uses camelCase continues to work.

```elixir
# Both of these send {"firstName": "Jane", "lastName": "Doe"}:
Humaans.People.create(client, %{first_name: "Jane", last_name: "Doe"})
Humaans.People.create(client, %{firstName: "Jane", lastName: "Doe"})
```

Atom and string input keys are normalized to string keys in the converted body (this avoids creating new atoms at runtime). Req JSON-encodes string-keyed maps transparently. Only top-level keys are converted; nested maps inside a body are left as-is.

### Webhooks

Verify HMAC-SHA256 signatures on incoming webhook deliveries with `Humaans.Webhooks.verify_signature/3`. Pass the **raw** request body (not the re-encoded JSON):

```elixir
case Humaans.Webhooks.verify_signature(raw_body, signature_header, secret) do
  :ok -> handle_event(raw_body)
  {:error, :invalid_signature} -> {:error, :unauthorized}
  {:error, :missing_signature} -> {:error, :unauthorized}
  {:error, :missing_secret} -> {:error, :misconfigured}
end
```

### Filtering with `Humaans.Query`

Build filter queries for list endpoints using the operator helpers in `Humaans.Query`:

```elixir
query =
  Humaans.Query.new()
  |> Humaans.Query.in_(:status, ["active", "onboarding"])
  |> Humaans.Query.gte(:createdAt, "2025-01-01")
  |> Humaans.Query.to_params()

{:ok, people} = Humaans.People.list(client, query)
```

Supported operators: `eq`, `in_`, `nin`, `gt`, `gte`, `lt`, `lte`. Use `Humaans.Query.merge/2` to combine a query with pagination params or another query.

### Available resources

- `Humaans.People` - Work with people resources
- `Humaans.AuditEvents` - Retrieve audit event resources (read-only)
- `Humaans.BankAccounts` - Work with bank account resources
- `Humaans.Companies` - Work with company resources
- `Humaans.CompensationTypes` - Work with compensation type resources
- `Humaans.Compensations` - Work with compensation resources
- `Humaans.CustomFields` - Work with custom field definitions
- `Humaans.CustomValues` - Work with custom value records
- `Humaans.DocumentFolders` - Work with document folder resources
- `Humaans.DocumentTypes` - Work with document type resources
- `Humaans.Documents` - Work with document resources
- `Humaans.EmergencyContacts` - Work with emergency contact resources
- `Humaans.EquipmentNames` - List equipment names (read-only)
- `Humaans.EquipmentTypes` - List equipment types (read-only)
- `Humaans.Equipment` - Work with equipment resources
- `Humaans.EsignBulkRecipients` - List and retrieve e-signature bulk recipient resources (read-only)
- `Humaans.EsignBulkTokens` - List and retrieve e-signature bulk token resources (read-only)
- `Humaans.EsignBulks` - List and retrieve e-signature bulk resources (read-only)
- `Humaans.EsignInstances` - List and retrieve e-signature instance resources (read-only)
- `Humaans.EsignTemplates` - List and retrieve e-signature template resources (read-only)
- `Humaans.IdentityDocumentTypes` - List identity document types (read-only)
- `Humaans.IdentityDocuments` - Work with identity document resources
- `Humaans.JobRoles` - Work with job role resources
- `Humaans.Locations` - Work with location resources
- `Humaans.OKRs` - List and retrieve OKR resources (read-only)
- `Humaans.PerformanceCyclePeerNominations` - Retrieve peer nomination resources (read-only)
- `Humaans.PerformanceCycles` - List and retrieve performance cycle resources (read-only)
- `Humaans.PerformanceInstances` - List and retrieve performance instance resources (read-only)
- `Humaans.PerformanceRatings` - Retrieve performance rating resources (read-only)
- `Humaans.PerformanceReviews` - List and retrieve performance review resources (read-only)
- `Humaans.PerformanceSummaries` - Retrieve performance summary resources (read-only)
- `Humaans.PerformanceTemplates` - List and retrieve performance template resources (read-only)
- `Humaans.PublicHolidayCalendarDays` - Work with public holiday calendar day resources
- `Humaans.PublicHolidayCalendars` - List public holiday calendars (read-only)
- `Humaans.PublicHolidays` - List public holidays (read-only)
- `Humaans.RequestActivityLogs` - List and retrieve request activity log resources (read-only)
- `Humaans.RequestComments` - List and retrieve request comment resources (read-only)
- `Humaans.RequestReviews` - List and retrieve request review resources (read-only)
- `Humaans.RequestTypes` - List and retrieve request type resources (read-only)
- `Humaans.Requests` - List and retrieve request resources (read-only)
- `Humaans.RoleMembers` - List and retrieve role member resources (read-only)
- `Humaans.RolePermissions` - List and retrieve role permission resources (read-only)
- `Humaans.Roles` - List and retrieve role resources (read-only)
- `Humaans.Spaces` - Work with space (team/department) resources
- `Humaans.Tasks` - List and retrieve task resources (read-only)
- `Humaans.TimeAwayAdjustments` - Work with time away adjustment resources
- `Humaans.TimeAwayAllocations` - Work with time away allocation resources
- `Humaans.TimeAwayPolicies` - Work with time away policy resources
- `Humaans.TimeAwayTypes` - Work with time away type resources
- `Humaans.TimeAway` - Work with time away resources
- `Humaans.TimesheetEntries` - Work with timesheet entry resources
- `Humaans.TimesheetSubmissions` - Work with timesheet submission resources
- `Humaans.WebhookEvents` - List and retrieve webhook event resources (read-only)
- `Humaans.Webhooks` - Work with webhook subscription resources
- `Humaans.WorkflowDependencies` - Retrieve workflow dependency resources (read-only)
- `Humaans.WorkflowFormResponses` - Retrieve workflow form response resources (read-only)
- `Humaans.WorkflowPublications` - Retrieve workflow publication resources (read-only)
- `Humaans.WorkflowSlackActions` - Retrieve workflow Slack action resources (read-only)
- `Humaans.WorkflowStats` - Retrieve workflow stat resources (read-only)
- `Humaans.WorkingPatternAllocations` - Work with working pattern allocation resources
- `Humaans.WorkingPatterns` - Work with working pattern resources
- `Humaans.Me` - Retrieve the authenticated user's profile (`GET /me`)
- `Humaans.TokenInfo` - Retrieve metadata about the current access token (`GET /token-info`)

## Development

### Requirements

- Elixir ~> 1.15
- [Homebrew](https://brew.sh) (for installing development tools)

### Setup

Run the setup script to install development tools and git hooks:

```shell
bin/setup
```

This installs `actionlint`, `check-jsonschema`, `lefthook`, and `markdownlint-cli2` via Homebrew, then configures the pre-commit hooks.

### Commands

| Command | Description |
| --- | --- |
| `mix setup` | Install dependencies |
| `mix test` | Run the test suite |
| `mix credo` | Run the linter |
| `mix format` | Format source files |

## License

Humaans is [released under the MIT license](LICENSE).

[humaans-api-docs]: https://docs.humaans.io/api/
