Setup
Add dependency
# mix.exs
def deps do
[
{:lattice_stripe, "~> 0.1"}
]
endCreate client
# In your supervision tree (application.ex):
children = [
{Finch, name: MyApp.Finch}
]
# Create a client:
client = LatticeStripe.Client.new!(
api_key: "sk_test_...",
finch: MyApp.Finch
)Payments
Create customer
{:ok, customer} = LatticeStripe.Customer.create(client, %{
"email" => "jenny@example.com",
"name" => "Jenny Rosen"
})
# Access fields:
customer.id # "cus_..."
customer.email # "jenny@example.com"Create PaymentIntent
{:ok, payment_intent} = LatticeStripe.PaymentIntent.create(client, %{
"amount" => 2000,
"currency" => "usd",
"payment_method" => "pm_card_visa",
"confirm" => true,
"automatic_payment_methods" => %{
"enabled" => true,
"allow_redirects" => "never"
}
})Checkout
Create session
{:ok, session} = LatticeStripe.Checkout.Session.create(client, %{
"mode" => "payment",
"success_url" => "https://example.com/success",
"cancel_url" => "https://example.com/cancel",
"line_items" => [
%{"price" => "price_xxx", "quantity" => 1}
]
})
# Redirect user to:
session.urlExpire session
{:ok, session} = LatticeStripe.Checkout.Session.expire(
client,
"cs_test_..."
)Webhooks
Verify event
raw_body = conn.assigns[:raw_body]
sig_header = Plug.Conn.get_req_header(conn, "stripe-signature")
|> List.first()
case LatticeStripe.Webhook.construct_event(
raw_body,
sig_header,
"whsec_test_..."
) do
{:ok, event} -> handle_event(event)
{:error, reason} -> {:error, reason}
endPlug setup (Phoenix router)
# In your router.ex, mount the webhook plug:
plug LatticeStripe.Webhook.Plug,
path: "/webhooks/stripe",
secret: Application.fetch_env!(:my_app, :stripe_webhook_secret),
handler: MyApp.StripeWebhookHandler
# Implement the handler:
defmodule MyApp.StripeWebhookHandler do
@behaviour LatticeStripe.Webhook.Handler
@impl true
def handle_event(%LatticeStripe.Event{type: "payment_intent.succeeded"} = event) do
# handle payment success
:ok
end
def handle_event(_event), do: :ok
endError Handling
Pattern match on errors
alias LatticeStripe.Error
case LatticeStripe.PaymentIntent.create(client, params) do
{:ok, payment_intent} ->
{:ok, payment_intent}
{:error, %Error{type: :card_error, message: msg}} ->
{:error, "Card declined: #{msg}"}
{:error, %Error{type: :rate_limit_error}} ->
{:error, "Rate limited — retry later"}
{:error, %Error{type: :auth_error}} ->
{:error, "Invalid API key"}
{:error, %Error{} = err} ->
{:error, "Stripe error: #{err.message}"}
endBang variants
# Raises LatticeStripe.Error on failure:
customer = LatticeStripe.Customer.create!(client, %{
"email" => "jenny@example.com"
})
payment_intent = LatticeStripe.PaymentIntent.retrieve!(
client,
"pi_..."
)Pagination
List with limit
{:ok, result} = LatticeStripe.Customer.list(client, %{
"limit" => 10
})
result.data # list of customers
result.has_more # true if more pages availableAuto-paginate with Stream
# Stream all customers, fetching pages lazily:
client
|> LatticeStripe.Customer.stream!(%{"limit" => 100})
|> Enum.take(50)
# Process all matching customers:
client
|> LatticeStripe.Customer.stream!(%{"email" => "jenny@example.com"})
|> Enum.each(&process_customer/1)Telemetry
Attach default logger
# In your application.ex start/2, after supervision tree:
LatticeStripe.Telemetry.attach_default_logger()
# With log level:
LatticeStripe.Telemetry.attach_default_logger(level: :debug)Telemetry events
# Events emitted by LatticeStripe:
[:lattice_stripe, :request, :start]
[:lattice_stripe, :request, :stop]
[:lattice_stripe, :request, :exception]
[:lattice_stripe, :webhook, :verify, :start]
[:lattice_stripe, :webhook, :verify, :stop]
[:lattice_stripe, :webhook, :verify, :exception]
# Attach a custom handler:
:telemetry.attach(
"my-handler",
[:lattice_stripe, :request, :stop],
fn _event, measurements, metadata, _config ->
Logger.info("Stripe #{metadata.method} #{metadata.path} #{measurements.duration}ns")
end,
nil
)