Polarex: Polar.sh Elixir Client
This library uses the Elixir OpenAPI Code Generator to turn the Polar.sh OpenAPI spec into an ergonomic client.
Installation
This library is available on Hex.pm.
Add the dependency in mix.exs:
def deps do
[
{:polarex, "~> 0.8.1"}
]
end
Then install the dependency using mix deps.get.
Configuration
This library will need the Polar.sh API base URL and your access token to work.
config :polarex,
server: "https://sandbox-api.polar.sh", # or "https://api.polar.sh" for production
access_token: "your_access_token",
req_options: [] # optional, merged into every underlying Req request
Every operation also accepts a req_options: option that wins over the
global one for that call.
Testing
req_options is the hook for stubbing HTTP in your tests with
Req.Test:
# config/test.exs
config :polarex, req_options: [plug: {Req.Test, Polarex}]
# in a test
Req.Test.expect(Polarex, fn conn ->
Req.Test.json(conn, %{"items" => [], "pagination" => %{"total_count" => 0, "max_page" => 0}})
end)
{:ok, %Polarex.ListResourceProduct{items: []}} = Polarex.Products.products_list([])
Errors
Every failure returns {:error, %Polarex.Error{}} with the HTTP status, a
human-readable message, the raw body, and on 422s the decoded
validation_errors:
{:error, %Polarex.Error{status: 422, validation_errors: [%Polarex.ValidationError{loc: ["body", "email"]} | _]}} =
Polarex.Customers.customers_create(%Polarex.CustomerIndividualCreate{email: "not-an-email"})
Transport failures (the request never got a response) have status: nil and
the reason (e.g. :econnrefused). Empty success bodies such as 204 No Content return {:ok, nil}.
Retries
Only GET requests are retried automatically (retry: :safe_transient).
Mutating requests (POST/PATCH/PUT/DELETE) are never retried by the library,
since repeating them can duplicate side effects such as checkouts. Opt in
explicitly through req_options if an endpoint is safe for your use case:
# retry this delete (idempotent on Polar's side) up to 3 times
Polarex.Customers.customers_delete("customer-id", req_options: [retry: :transient, max_retries: 3])
Any Req retry option works,
including a custom retry: fn request, response_or_error -> ... end.
Telemetry
Every request emits [:polarex, :request, :start | :stop | :exception]
telemetry events. The metadata includes :operation (e.g.
{Polarex.Checkouts, :checkouts_create}), :method and :url, so you can
attach handlers for logging or metrics without wrapping the client.
API versioning
Polar versions its API by date (e.g. 2026-04) and selects the version by
SDK generation rather than an HTTP header: the behavior you get matches the
OpenAPI spec this library was generated from. Check the info.version field
of the bundled openapi.json for the current one.
Usage
All of the client operations are generated based on the OpenAPI description provided by Polar.sh. In general, you can expect to find:
Polarex.Resource.operation(...)
Where:
Resourceis the name of the resource such asCheckouts.operationis the name of the route, such ascheckouts_list.- Besides their specific arguments, all operations accept a keyword list of options.
So to list all checkouts, you would use:
Polarex.Checkouts.checkouts_list([])
Contributing
Because this library uses a code generator for the majority of its mass, there are two modes of contribution. Please consider these when creating issues or opening pull requests:
- If the generated code is out of date, there is a mix task
mix sdk.buildthat will pull the latest spec and generate the code. - In the the support folder there is a req client that does the actual HTTP requests. If you find a bug or want to improve it (e.g. adding telemetry), you can add to
Polarex.Support.Clientand open a pull request.