Humaans

Build StatusCoverage StatusHex VersionHex Docs

An Elixir client for the Humaans API.

Installation

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

def deps do
[
{:humaans, "~> 0.6.0"}
]
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:

# 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 client (timeouts, retries, plugins, etc.):

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.

Module access helpers

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

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.

# 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):

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:

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

Development

Requirements

Setup

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

bin/setup

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

Commands

CommandDescription
mix setupInstall dependencies
mix testRun the test suite
mix credoRun the linter
mix formatFormat source files

License

Humaans is released under the MIT license.