The main entry point for making Stripe API requests.
Client is a plain struct (no GenServer, no global state) that holds all
configuration for a Stripe integration. Create one at application startup
and pass it explicitly to every API call.
Quick Start
client = LatticeStripe.Client.new!(
api_key: "sk_test_...",
finch: MyApp.Finch
)
request = %LatticeStripe.Request{method: :get, path: "/v1/customers/cus_123"}
{:ok, customer} = LatticeStripe.Client.request(client, request)Multiple Clients
You can run multiple clients with different keys simultaneously — useful for Stripe Connect platforms managing sub-accounts:
platform_client = LatticeStripe.Client.new!(api_key: "sk_live_platform", finch: MyApp.Finch)
connect_client = LatticeStripe.Client.new!(
api_key: "sk_live_platform",
finch: MyApp.Finch,
stripe_account: "acct_connected_account"
)Per-Request Overrides
Pass opts in a Request struct to override client defaults for a single call:
request = %LatticeStripe.Request{
method: :post,
path: "/v1/charges",
params: %{amount: 1000, currency: "usd", source: "tok_visa"},
opts: [
idempotency_key: "charge-unique-key-123",
stripe_account: "acct_connected",
timeout: 10_000
]
}
Summary
Functions
Creates a new %Client{} struct, returning {:ok, client} or {:error, error}.
Creates a new %Client{} struct, raising on invalid options.
Dispatches a Request through the client's configured transport with automatic retries.
Like request/2, but raises LatticeStripe.Error on failure.
Types
@type t() :: %LatticeStripe.Client{ api_key: String.t(), api_version: String.t(), base_url: String.t(), finch: atom(), json_codec: module(), max_retries: non_neg_integer(), retry_strategy: module(), stripe_account: String.t() | nil, telemetry_enabled: boolean(), timeout: pos_integer(), transport: module() }
A configured LatticeStripe client.
Created via new!/1 or new/1. Pass this struct to every API call.
It is a plain struct with no process state — safe to share across processes.
api_key- Stripe secret key (sk_test_...orsk_live_...)finch- Name of the Finch pool started in your supervision treestripe_account- Connected account ID for Stripe Connect platforms, ornilbase_url- Stripe API base URL (default:"https://api.stripe.com")api_version- Stripe API version header (default:"2026-03-25.dahlia")transport- Transport module implementingLatticeStripe.Transportjson_codec- JSON codec module implementingLatticeStripe.Jsonretry_strategy- Retry strategy module implementingLatticeStripe.RetryStrategytimeout- Default request timeout in milliseconds (default:30_000)max_retries- Max retry attempts after initial failure (default:2)telemetry_enabled- Whether to emit telemetry events (default:true)
Functions
@spec new(keyword()) :: {:ok, t()} | {:error, NimbleOptions.ValidationError.t()}
Creates a new %Client{} struct, returning {:ok, client} or {:error, error}.
Like new!/1 but returns a result tuple instead of raising.
Example
case LatticeStripe.Client.new(api_key: "sk_test_...", finch: MyApp.Finch) do
{:ok, client} -> client
{:error, error} -> raise error
end
Creates a new %Client{} struct, raising on invalid options.
Validates options using LatticeStripe.Config.validate!/1. Raises
NimbleOptions.ValidationError with a descriptive message if any option
is invalid or a required option is missing.
Required Options
:api_key- Your Stripe API key (e.g.,"sk_test_..."):finch- Name atom of a running Finch pool (e.g.,MyApp.Finch)
Optional Options
See LatticeStripe.Config for the full schema with defaults and documentation.
Example
client = LatticeStripe.Client.new!(api_key: "sk_test_...", finch: MyApp.Finch)
@spec request(t(), LatticeStripe.Request.t()) :: {:ok, LatticeStripe.Response.t()} | {:error, LatticeStripe.Error.t()}
Dispatches a Request through the client's configured transport with automatic retries.
Builds the full request with all required headers, encodes params, calls
the transport, decodes the response JSON, and returns either {:ok, map}
on success or {:error, %Error{}} on failure.
POST requests automatically get an idk_ltc_-prefixed UUID v4 idempotency key
to make retries safe. The same key is reused across all retry attempts.
User-provided :idempotency_key in opts takes precedence over auto-generation.
Wraps the transport call(s) in a :telemetry.span/3 for observability (unless
telemetry_enabled: false on the client). Per-retry events are emitted as
[:lattice_stripe, :request, :retry].
Parameters
client- A%LatticeStripe.Client{}structrequest- A%LatticeStripe.Request{}struct
Returns
{:ok, %LatticeStripe.Response{}}- Response struct wrapping decoded data with metadata.datais a%LatticeStripe.List{}for list/search endpoints, or a plain map for singular resources.{:error, %LatticeStripe.Error{}}- Structured error from 4xx/5xx or transport failure
@spec request!(t(), LatticeStripe.Request.t()) :: LatticeStripe.Response.t()
Like request/2, but raises LatticeStripe.Error on failure.
Retries are attempted first. Only raises after all retries are exhausted.
Parameters
client- A%LatticeStripe.Client{}structrequest- A%LatticeStripe.Request{}struct
Returns
%LatticeStripe.Response{}on success (raisesLatticeStripe.Erroron failure)- Raises
LatticeStripe.Erroron failure (after retries exhausted)