
HawkEx is an Elixir toolkit for SaaS billing infrastructure. It provides Ecto schemas and service modules for plans, subscriptions, entitlements, audit logging, CSV exports, and lightweight operational queries.
The library is designed to live inside a Phoenix application. Your app owns the account schema, payment provider integration, authentication, and usage tracking. HawkEx owns the durable billing records and the small APIs needed to answer common questions such as "does this account have access?" and "what is left on this plan?"
Features
- Plan and subscription records with trial, active, past due, and canceled states.
- Entitlement checks for boolean and limit-based features.
- Optional PubSub events for subscription lifecycle changes.
- Audit log records for billing events and application-defined actions.
- Synchronous CSV exports and optional async exports through Oban.
- Pluggable CSV storage, with local disk and S3 adapters.
- Shared pagination helpers for dashboard-style views.
Dashboard
You can use hawk_ex_dashboard alongside HawkEx to add an admin-facing Phoenix dashboard. It provides a UI for viewing and managing subscriptions, entitlements, audit logs, CSV exports, and related operational data powered by this library.
Installation
Add hawk_ex to your dependencies:
def deps do
[
{:hawk_ex, "~> 0.1.0"}
]
endThen copy the migrations:
mix hawk_ex.install
mix ecto.migrate
Configuration
At minimum, configure the Ecto repo and the schema that represents the billable account in your application:
config :hawk_ex,
repo: MyApp.Repo,
account_schema: MyApp.Accounts.OrganizationOptional integrations:
config :hawk_ex,
pubsub: MyApp.PubSub,
oban: Oban,
csv_storage: {HawkEx.CSV.Storage.Local, path: "priv/exports"}For S3-backed CSV exports:
config :hawk_ex,
csv_storage: {HawkEx.CSV.Storage.S3,
bucket: "my-app-exports",
prefix: "exports/"}Entitlements
Use the top-level HawkEx module for the most common access checks:
if HawkEx.allowed?(account, :export_csv) do
export_csv()
end
case HawkEx.remaining(account, :api_calls) do
:unlimited -> allow_request()
count when count > 0 -> allow_request()
_ -> deny_request()
endremaining/2 returns the limit configured on the account's current plan. It
does not count usage. Your application should store and subtract usage for
metered features.
Billing
Subscriptions are managed through HawkEx.Billing:
{:ok, subscription} = HawkEx.Billing.subscribe(account, :pro)
{:ok, canceled} = HawkEx.Billing.cancel(account)
{:ok, changed} = HawkEx.Billing.change_plan(account, :enterprise)HawkEx keeps canceled subscriptions for history. New subscriptions create new
records, while change_plan/2 updates the active subscription in place in the
current release.
CSV Exports
Small exports can be generated synchronously:
{:ok, csv, row_count} = HawkEx.CSV.export(account, :subscriptions)Async exports require Oban to be installed and configured:
{:ok, export} = HawkEx.CSV.export_async(account, :audit_logs)Custom exports implement the HawkEx.CSV.Formatter behaviour.
Audit Logs
Record application actions with:
HawkEx.Audit.track(current_user, "settings.updated", organization)When PubSub is configured, HawkEx also records its own subscription lifecycle events through the audit listener.
Documentation
Generate local documentation with:
mix docs
Published package documentation will be available on HexDocs after release.
Contributing
Contributions are welcome. Please keep changes focused, include tests for new or changed behavior, and run the checks before opening a pull request:
mix format
mix test
mix docs
For larger changes, open an issue or discussion first so the design can be aligned before implementation.
License
HawkEx is released under the MIT License. See LICENSE for details.