defmodule Paysafe do
@moduledoc """
Production-grade Elixir client for the Paysafe API.
## Overview
This library provides complete coverage of the Paysafe developer platform:
- **Payments API** — Payment handles, payments, settlements, refunds, payouts,
verifications, and customer/vault management.
- **Payment Scheduler API** — Plans and subscriptions for recurring billing.
- **Applications API** — Programmatic merchant onboarding.
- **Value Added Services** — FX Rates, Customer Identity (KYC), Bank Account
Validation, Network Tokenization, Account Updater.
- **Webhooks** — HMAC-SHA256 verification and typed event parsing.
## Configuration
Build a config struct from your credentials:
config = Paysafe.Config.new!(
username: "1001062690",
password: "B-qa2-0-...",
environment: :test,
account_id: "1009688230"
)
Or load from `config/config.exs`:
# config/config.exs
config :paysafe,
username: System.get_env("PAYSAFE_USERNAME"),
password: System.get_env("PAYSAFE_PASSWORD"),
environment: :test,
account_id: "1009688230"
# runtime:
config = Paysafe.Config.from_env!()
## Quick start — card payment
config = Paysafe.Config.new!(
username: "...",
password: "...",
environment: :test,
account_id: "1009688230"
)
# 1. Create a payment handle
{:ok, handle} = Paysafe.create_payment_handle(config, %{
merchant_ref_num: "order-#{:rand.uniform(999_999)}",
amount: 5000,
currency_code: "USD",
payment_type: "CARD",
transaction_type: "PAYMENT",
card: %{
card_num: "4111111111111111",
card_expiry: %{month: 12, year: 2030},
cvv: "123",
holder_name: "Jane Doe"
},
billing_details: %{
street: "123 Main St",
city: "New York",
state: "NY",
country: "US",
zip: "10001"
},
settle_with_auth: true
})
# 2. Use the token in a payment
{:ok, payment} = Paysafe.create_payment(config, %{
merchant_ref_num: "payment-001",
amount: 5000,
currency_code: "USD",
settle_with_auth: true,
payment_handle_token: handle.payment_handle_token
})
## Payment method coverage
The Payments API supports 30+ payment methods:
- **Cards** — Visa, Mastercard, Amex, Discover, Debit, Prepaid, Corporate.
- **Digital Wallets** — Apple Pay, Google Pay, PayPal, Venmo, Skrill, Neteller.
- **Bank Transfers** — iDEAL, EPS, BLIK, Interac e-Transfer, Mazooma, Pay by Bank.
- **Direct Debit** — ACH (US), BACS (UK), EFT (CA), SEPA (EU).
- **Cash** — PaysafeCash.
- **Vouchers** — PaysafeCard, Openbucks, Multibanco.
- **LatAm** — SafetyPay (Pix, Boleto, KHIPU, MACH), PagoEfectivo, Rapid Transfer.
- **Crypto** — Pay with Crypto.
## Architecture
- Config validated at construction via `NimbleOptions`.
- All requests have exponential backoff retry on transient failures.
- Token-bucket rate limiting per account via `ExRated`.
- Telemetry events on every request (`:paysafe, :request, :start/:stop/:exception`).
- HMAC-SHA256 webhook verification with constant-time comparison.
- All public functions return `{:ok, result} | {:error, %Paysafe.Error{}}`.
"""
alias Paysafe.Payments.{
Customers,
PaymentHandles,
Payments,
Payouts,
Refunds,
Settlements,
Verifications
}
alias Paysafe.Scheduler.{Plans, Subscriptions}
alias Paysafe.Webhooks
# ── Payments API ─────────────────────────────────────────────────────────────
@doc """
Create a payment handle (tokenize a payment instrument).
See `Paysafe.Payments.PaymentHandles.create/3` for full parameter docs.
"""
defdelegate create_payment_handle(config, params, opts \\ []), to: PaymentHandles, as: :create
@doc """
Retrieve a payment handle by ID.
"""
defdelegate get_payment_handle(config, handle_id, opts \\ []), to: PaymentHandles, as: :get
@doc """
Create a payment using a `paymentHandleToken`.
See `Paysafe.Payments.Payments.create/3` for full parameter docs.
"""
defdelegate create_payment(config, params, opts \\ []), to: Payments, as: :create
@doc """
Retrieve a payment by ID.
"""
defdelegate get_payment(config, payment_id, opts \\ []), to: Payments, as: :get
@doc """
List payments with optional filters.
"""
defdelegate list_payments(config, opts \\ []), to: Payments, as: :list
@doc """
Cancel an authorized (pre-settlement) payment.
"""
defdelegate cancel_payment(config, payment_id, opts \\ []), to: Payments, as: :cancel
@doc """
Create a settlement for an authorized payment.
"""
defdelegate create_settlement(config, payment_id, params, opts \\ []),
to: Settlements,
as: :create
@doc """
Cancel a pending settlement.
"""
defdelegate cancel_settlement(config, settlement_id, opts \\ []),
to: Settlements,
as: :cancel
@doc """
Issue a refund for a completed payment or settlement.
Pass the settlement ID (or the payment ID, if `settle_with_auth` was
`true` on the original payment).
"""
defdelegate create_refund(config, settlement_id, params, opts \\ []), to: Refunds, as: :create
@doc """
Cancel a pending refund.
"""
defdelegate cancel_refund(config, refund_id, opts \\ []), to: Refunds, as: :cancel
@doc """
Create a standalone credit (payout for non-iGaming merchants).
"""
defdelegate standalone_credit(config, params, opts \\ []), to: Payouts, as: :standalone_credit
@doc """
Create an original credit (payout for iGaming merchants).
"""
defdelegate original_credit(config, params, opts \\ []), to: Payouts, as: :original_credit
@doc """
Create a card verification (zero-value auth check).
"""
defdelegate create_verification(config, params, opts \\ []), to: Verifications, as: :create
@doc """
Create a customer profile in the vault.
"""
defdelegate create_customer(config, params, opts \\ []), to: Customers, as: :create
@doc """
Retrieve a customer profile.
"""
defdelegate get_customer(config, customer_id, opts \\ []), to: Customers, as: :get
@doc """
Retrieve a customer profile by your own `merchantCustomerId`.
"""
defdelegate get_customer_by_merchant_customer_id(config, merchant_customer_id, opts \\ []),
to: Customers,
as: :get_by_merchant_customer_id
@doc """
Update a customer profile.
"""
defdelegate update_customer(config, customer_id, params, opts \\ []),
to: Customers,
as: :update
@doc """
Delete a customer profile.
"""
defdelegate delete_customer(config, customer_id, opts \\ []), to: Customers, as: :delete
@doc """
Create a multi-use payment handle (saved instrument) for a customer.
"""
defdelegate create_customer_payment_handle(config, customer_id, params, opts \\ []),
to: Customers,
as: :create_payment_handle
@doc """
List saved payment handles for a customer.
"""
defdelegate list_customer_payment_handles(config, customer_id, opts \\ []),
to: Customers,
as: :list_payment_handles
@doc """
Create a single-use customer token (SUCT), tokenizing a customer's entire
saved profile (cards, addresses, bank mandates) for 900 seconds.
"""
defdelegate create_single_use_customer_token(config, customer_id, opts \\ []),
to: Customers,
as: :create_single_use_customer_token
# ── Scheduler API ─────────────────────────────────────────────────────────────
@doc """
Create a recurring billing plan.
See `Paysafe.Scheduler.Plans.create/3` for full parameter docs.
"""
defdelegate create_plan(config, params, opts \\ []), to: Plans, as: :create
@doc """
Retrieve a billing plan by ID.
"""
defdelegate get_plan(config, plan_id, opts \\ []), to: Plans, as: :get
@doc """
List all billing plans.
"""
defdelegate list_plans(config, opts \\ []), to: Plans, as: :list
@doc """
Update a billing plan.
"""
defdelegate update_plan(config, plan_id, params, opts \\ []), to: Plans, as: :update
@doc """
Delete (discontinue) a billing plan.
"""
defdelegate delete_plan(config, plan_id, opts \\ []), to: Plans, as: :delete
@doc """
Create a subscription for a customer under a plan.
See `Paysafe.Scheduler.Subscriptions.create/3` for full parameter docs.
"""
defdelegate create_subscription(config, params, opts \\ []), to: Subscriptions, as: :create
@doc """
Retrieve a subscription by ID.
"""
defdelegate get_subscription(config, subscription_id, opts \\ []),
to: Subscriptions,
as: :get
@doc """
List subscriptions.
"""
defdelegate list_subscriptions(config, opts \\ []), to: Subscriptions, as: :list
@doc """
Update a subscription.
"""
defdelegate update_subscription(config, subscription_id, params, opts \\ []),
to: Subscriptions,
as: :update
@doc """
Cancel a subscription.
"""
defdelegate cancel_subscription(config, subscription_id, opts \\ []),
to: Subscriptions,
as: :cancel
@doc """
Suspend a subscription (billing paused; can be re-activated).
"""
defdelegate suspend_subscription(config, subscription_id, opts \\ []),
to: Subscriptions,
as: :suspend
@doc """
Re-activate a suspended subscription.
"""
defdelegate reactivate_subscription(config, subscription_id, opts \\ []),
to: Subscriptions,
as: :reactivate
# ── Webhooks ─────────────────────────────────────────────────────────────────
@doc """
Verify the HMAC-SHA256 signature and parse a webhook payload.
See `Paysafe.Webhooks.verify_and_parse/3` for full docs.
"""
defdelegate verify_webhook(raw_body, signature, hmac_key), to: Webhooks, as: :verify_and_parse
@doc """
Parse a verified webhook body.
"""
defdelegate parse_webhook(raw_body), to: Webhooks, as: :parse
# ── Convenience helpers ────────────────────────────────────────────────────
@doc """
Check if a `PaymentHandle` requires a customer redirect.
Returns `{:redirect, url}` or `:proceed`.
## Example
{:ok, handle} = Paysafe.create_payment_handle(config, params)
case Paysafe.handle_action(handle) do
{:redirect, url} -> redirect(conn, url)
:proceed -> create_payment(config, payment_params)
end
"""
@spec handle_action(Paysafe.Types.PaymentHandle.t()) :: {:redirect, String.t()} | :proceed
def handle_action(%Paysafe.Types.PaymentHandle{action: :redirect, links: links}) do
redirect_url =
Enum.find_value(links, fn
%{"rel" => "payment_redirect", "href" => href} -> href
_ -> nil
end)
{:redirect, redirect_url}
end
def handle_action(%Paysafe.Types.PaymentHandle{action: :none}), do: :proceed
def handle_action(%Paysafe.Types.PaymentHandle{}), do: :proceed
@doc """
Returns the currently configured package version.
"""
@spec version() :: String.t()
def version, do: Application.spec(:paysafe, :vsn) |> to_string()
end