Skip to main content

lib/treasury_prime.ex

defmodule TreasuryPrime do
  @moduledoc """
  An unofficial, complete Elixir client for the [Treasury Prime](https://www.treasuryprime.com)
  banking API (the Ledger product) — bank accounts, ACH, wires, book
  transfers, FedNow, cards, account opening / KYC, check deposit (RDC),
  check issuing, webhooks, sandbox simulations, and more.

  This module just re-exports `TreasuryPrime.Client.new/1` for convenience.
  Everything else lives in resource-specific modules named after the
  Treasury Prime object they wrap: `TreasuryPrime.Account`,
  `TreasuryPrime.Ach`, `TreasuryPrime.Wire`, `TreasuryPrime.Card`, and so on
  — see the docs sidebar for the full list, grouped by area.

  ## Quick start

      client =
        TreasuryPrime.new(
          api_key_id: System.fetch_env!("TREASURY_PRIME_KEY_ID"),
          api_key_value: System.fetch_env!("TREASURY_PRIME_KEY_VALUE"),
          environment: :sandbox
        )

      {:ok, page} = TreasuryPrime.Account.list(client)
      Enum.each(page.data, &IO.inspect/1)

      {:ok, ach} =
        TreasuryPrime.Ach.create(
          client,
          %{
            account_id: "acct_123456",
            counterparty_id: "cp_098765",
            amount: "100.00",
            direction: "credit",
            sec_code: "ccd"
          },
          idempotency_key: TreasuryPrime.Idempotency.generate_key()
        )

  ## Design notes

    * **Every function comes in a non-raising and a raising flavor.**
      `TreasuryPrime.Account.get/2` returns `{:ok, account} | {:error, error}`;
      `TreasuryPrime.Account.get!/2` returns the account or raises a
      `TreasuryPrime.Error`.
    * **Zero required HTTP dependency.** The default transport is built on
      Erlang's own `:httpc`/`:ssl` (see `TreasuryPrime.HTTPClient.Httpc`).
      Plug in Req, Finch, or anything else by implementing the one-callback
      `TreasuryPrime.HTTPClient` behaviour and passing
      `http_client: YourAdapter` to `new/1`.
    * **Pagination is lazy.** `list/2` functions return a `TreasuryPrime.Page`;
      call `TreasuryPrime.Page.stream/1` to get a lazy `Stream` over every
      result across every page.
    * **Nested/embedded objects** (addresses, card controls, IMAD/OMAD wire
      tracing info, etc.) are kept as plain string-keyed maps rather than
      further nested structs, to keep the library's surface area
      manageable — only top-level resource fields are typed struct fields.
    * **Unknown response fields are ignored, not errors.** Treasury Prime
      can add fields to responses over time; this library won't break when
      that happens.
  """

  alias TreasuryPrime.Client

  @doc "Alias for `TreasuryPrime.Client.new/1`."
  @spec new(keyword()) :: Client.t()
  def new(opts), do: Client.new(opts)
end