Packages

Production-grade Elixir client for the Paysafe API

Current section

Files

Jump to
paysafe lib paysafe config.ex
Raw

lib/paysafe/config.ex

defmodule Paysafe.Config do
@moduledoc """
Configuration for the Paysafe client.
## Options
* `:username` - (required) API username from the Paysafe Business Portal.
* `:password` - (required) API password from the Paysafe Business Portal.
* `:environment` - `:test` or `:production`. Defaults to `:test`.
* `:account_id` - Default account ID for requests. Can be overridden per-call.
* `:base_url_override` - Override the computed base URL entirely. Primarily
intended for testing (pointing at a local mock server) or routing through
a corporate proxy. When set, this replaces the `:environment`-derived
base URL for every API (Payments, Scheduler, Applications, etc).
* `:http_options` - Options passed directly to `Req`. Defaults to `[]`.
* `:timeout` - Request timeout in milliseconds. Defaults to `30_000`.
* `:recv_timeout` - Receive timeout in milliseconds. Defaults to `30_000`.
* `:max_retries` - Maximum number of retries on transient failures. Defaults to `3`.
* `:retry_delay` - Base delay in ms between retries (exponential backoff). Defaults to `500`.
* `:rate_limit` - `{scale_ms, limit}` tuple for token bucket rate limiting. Defaults to `{1_000, 100}`.
* `:telemetry_prefix` - Telemetry event prefix. Defaults to `[:paysafe]`.
## Example
config :paysafe,
username: "1001062690",
password: "B-qa2-0-...",
environment: :test,
account_id: "1009688230"
"""
@base_urls %{
test: "https://api.test.paysafe.com",
production: "https://api.paysafe.com"
}
@payments_path "/paymenthub/v1"
@scheduler_path "/subscriptionsplans/v1"
@applications_path "/merchant/v1"
@customer_vault_path "/customervault/v1"
@fx_rates_path "/fxrates/v1"
@direct_debit_path "/directdebit/v1"
@cards_path "/cardpayments/v1"
@bank_account_validator_path "/bankaccountvalidator/v1"
@customer_identification_path "/customeridentification/v1"
@schema NimbleOptions.new!(
username: [
type: :string,
required: true,
doc: "API username from the Paysafe Business Portal."
],
password: [
type: :string,
required: true,
doc: "API password from the Paysafe Business Portal."
],
environment: [
type: {:in, [:test, :production]},
default: :test,
doc: "The environment to connect to."
],
account_id: [
type: {:or, [:string, nil]},
default: nil,
doc: "Default account ID. Can be overridden per-call."
],
base_url_override: [
type: {:or, [:string, nil]},
default: nil,
doc: "Override the computed base URL entirely (testing/proxy use cases)."
],
timeout: [
type: :pos_integer,
default: 30_000,
doc: "Request timeout in milliseconds."
],
recv_timeout: [
type: :pos_integer,
default: 30_000,
doc: "Receive timeout in milliseconds."
],
max_retries: [
type: :non_neg_integer,
default: 3,
doc: "Maximum number of retries on transient failures."
],
retry_delay: [
type: :pos_integer,
default: 500,
doc: "Base delay in ms between retries (exponential backoff)."
],
rate_limit: [
type: {:tuple, [:pos_integer, :pos_integer]},
default: {1_000, 100},
doc: "{scale_ms, limit} for token bucket rate limiting."
],
telemetry_prefix: [
type: {:list, :atom},
default: [:paysafe],
doc: "Telemetry event prefix."
],
http_options: [
type: :keyword_list,
default: [],
doc: "Extra options passed to Req."
]
)
@type t :: %__MODULE__{
username: String.t(),
password: String.t(),
environment: :test | :production,
account_id: String.t() | nil,
base_url_override: String.t() | nil,
timeout: pos_integer(),
recv_timeout: pos_integer(),
max_retries: non_neg_integer(),
retry_delay: pos_integer(),
rate_limit: {pos_integer(), pos_integer()},
telemetry_prefix: [atom()],
http_options: keyword()
}
defstruct [
:username,
:password,
:account_id,
:base_url_override,
environment: :test,
timeout: 30_000,
recv_timeout: 30_000,
max_retries: 3,
retry_delay: 500,
rate_limit: {1_000, 100},
telemetry_prefix: [:paysafe],
http_options: []
]
@doc """
Build and validate a `Config` struct from a keyword list or map.
Raises `NimbleOptions.ValidationError` on invalid input.
"""
@spec new!(keyword() | map()) :: t()
def new!(opts) when is_map(opts), do: opts |> Map.to_list() |> new!()
def new!(opts) do
validated = NimbleOptions.validate!(opts, @schema)
struct!(__MODULE__, validated)
end
@doc """
Load config from the application environment and merge with any overrides.
"""
@spec from_env!(keyword()) :: t()
def from_env!(overrides \\ []) do
env_opts = Application.get_all_env(:paysafe)
Keyword.merge(env_opts, overrides) |> new!()
end
@doc """
Returns the full base URL for the configured environment, or
`base_url_override` if set.
"""
@spec base_url(t()) :: String.t()
def base_url(%__MODULE__{base_url_override: override}) when is_binary(override), do: override
def base_url(%__MODULE__{environment: env}), do: Map.fetch!(@base_urls, env)
@doc """
Returns the Payments API base URL.
"""
@spec payments_url(t()) :: String.t()
def payments_url(config), do: base_url(config) <> @payments_path
@doc """
Returns the Payment Scheduler API base URL.
"""
@spec scheduler_url(t()) :: String.t()
def scheduler_url(config), do: base_url(config) <> @scheduler_path
@doc """
Returns the Applications (Onboarding) API base URL.
"""
@spec applications_url(t()) :: String.t()
def applications_url(config), do: base_url(config) <> @applications_path
@doc """
Returns the Customer Vault API base URL.
"""
@spec customer_vault_url(t()) :: String.t()
def customer_vault_url(config), do: base_url(config) <> @customer_vault_path
@doc """
Returns the FX Rates API base URL.
"""
@spec fx_rates_url(t()) :: String.t()
def fx_rates_url(config), do: base_url(config) <> @fx_rates_path
@doc """
Returns the Direct Debit API base URL.
"""
@spec direct_debit_url(t()) :: String.t()
def direct_debit_url(config), do: base_url(config) <> @direct_debit_path
@doc """
Returns the Cards API base URL.
"""
@spec cards_url(t()) :: String.t()
def cards_url(config), do: base_url(config) <> @cards_path
@doc """
Returns the Bank Account Validator API base URL (also used by the Interac
Verification Service, which lives under `/verifiedme` on the same base).
"""
@spec bank_account_validator_url(t()) :: String.t()
def bank_account_validator_url(config), do: base_url(config) <> @bank_account_validator_path
@doc """
Returns the Customer Identification (KYC) API base URL.
"""
@spec customer_identification_url(t()) :: String.t()
def customer_identification_url(config), do: base_url(config) <> @customer_identification_path
@doc """
Computes the Base64-encoded Basic Auth header value.
"""
@spec auth_header(t()) :: String.t()
def auth_header(%__MODULE__{username: u, password: p}) do
"Basic " <> Base.encode64("#{u}:#{p}")
end
@doc """
Returns the NimbleOptions schema for external inspection.
"""
@spec schema() :: NimbleOptions.t()
def schema, do: @schema
end