Stripe Charge objects — the result record of a payment attempt.
When a LatticeStripe.PaymentIntent is confirmed, Stripe creates a Charge that
captures the settled payment outcome. New integrations should start with
LatticeStripe.PaymentIntent for accepting payments; this module is for reading
and reconciling those result records after the fact.
When to use this module
- Connect platform fee reconciliation — walk
balance_transaction.fee_detailsafter a destination charge settles to reconcile application fees. - Support and audit workflows —
list/3,stream!/3, andsearch/3to find charges by customer, date, or Stripe search query. - Post-hoc metadata —
update/4to attach or correctmetadataanddescriptionon an existing charge without re-running payment flows.
When not to use this module
- Accept a payment →
LatticeStripe.PaymentIntent.create/3 - Capture a PI-initiated charge →
LatticeStripe.PaymentIntent.capture/4 - Cancel a payment →
LatticeStripe.PaymentIntent.cancel/4 - Refund a charge →
LatticeStripe.Refund.create/3
Usage
client = LatticeStripe.Client.new!(api_key: "sk_live_...", finch: MyApp.Finch)
# Retrieve a settled charge by id (expand balance_transaction for fee_details)
{:ok, charge} =
LatticeStripe.Charge.retrieve(client, "ch_3OoLqrJ...",
expand: ["balance_transaction"]
)
# List charges with filters
{:ok, resp} = LatticeStripe.Charge.list(client, %{"limit" => "20", "customer" => "cus_123"})
# Stream all charges lazily (auto-pagination)
client
|> LatticeStripe.Charge.stream!()
|> Stream.take(100)
|> Enum.each(&process_charge/1)
# Search charges (eventual consistency — new charges may lag)
{:ok, resp} = LatticeStripe.Charge.search(client, "status:'succeeded' AND currency:'usd'")
# Update metadata and description on an existing charge
{:ok, charge} =
LatticeStripe.Charge.update(client, "ch_3OoLqrJ...", %{
"metadata" => %{"order_id" => "ord_456"},
"description" => "Order #456"
})
# Capture an uncaptured legacy direct charge (not PI-initiated)
{:ok, charge} = LatticeStripe.Charge.capture(client, "ch_3OoLqrJ...")Connect platform fee reconciliation
After a destination charge settles, platforms walk
PaymentIntent.latest_charge -> Charge.balance_transaction -> fee_details to
reconcile the application fee Stripe transferred into their platform balance.
The typed %Charge{} return gives IDE-friendly completion and typespec coverage
for that flow without forcing users to drop into LatticeStripe.Client.request/2.
# Walk fee_details to find the application_fee entry (Connect platform fee)
application_fees =
charge.balance_transaction["fee_details"]
|> Enum.filter(fn fd -> fd["type"] == "application_fee" end)SDK surface (intentionally omitted)
There is no create/3 or cancel/3 — this module does not initiate payments.
Charges are created as a side effect of PaymentIntent confirmation (or legacy
direct-charge flows outside this SDK). See Phase 18 decision D-06 for the
payment-initiation rationale.
Security and Inspect
Inspect shows only [id, object, amount, currency, status, captured, paid].
The following fields may contain customer PII and are hidden from inspect
output so they do not leak into application logs:
billing_details(email, name, phone, address)payment_method_details(card last4, fingerprint, etc.)fraud_detailsreceipt_email,receipt_number,receipt_urlcustomer,payment_method
If you explicitly access those fields on a %Charge{} struct, you own the
disclosure decision.
Stripe API Reference
See the Stripe Charge API for the full object reference.
Summary
Functions
Captures an uncaptured Charge.
Like capture/4 but raises LatticeStripe.Error on failure.
Converts a decoded Stripe API map to a %Charge{} struct.
Lists Charges with optional filters.
Like list/3 but raises LatticeStripe.Error on failure.
Retrieves a Charge by ID.
Like retrieve/3 but returns the bare %Charge{} on success and raises
LatticeStripe.Error on failure.
Searches Charges using Stripe's search query language.
Like search/3 but raises LatticeStripe.Error on failure.
Returns a lazy stream of all Charges matching the search query (auto-pagination).
Returns a lazy stream of all Charges matching the given params (auto-pagination).
Updates a Charge by ID.
Like update/4 but raises LatticeStripe.Error on failure.
Types
@type t() :: %LatticeStripe.Charge{ amount: integer() | nil, amount_captured: integer() | nil, amount_refunded: integer() | nil, application: String.t() | nil, application_fee: String.t() | nil, application_fee_amount: integer() | nil, balance_transaction: LatticeStripe.BalanceTransaction.t() | String.t() | nil, billing_details: map() | nil, captured: boolean() | nil, created: integer() | nil, currency: String.t() | nil, customer: LatticeStripe.Customer.t() | String.t() | nil, description: String.t() | nil, destination: LatticeStripe.Account.t() | String.t() | nil, extra: map(), failure_code: String.t() | nil, failure_message: String.t() | nil, fraud_details: map() | nil, id: String.t() | nil, invoice: LatticeStripe.Invoice.t() | String.t() | nil, livemode: boolean() | nil, metadata: map() | nil, object: String.t(), on_behalf_of: String.t() | nil, outcome: map() | nil, paid: boolean() | nil, payment_intent: LatticeStripe.PaymentIntent.t() | String.t() | nil, payment_method: LatticeStripe.PaymentMethod.t() | String.t() | nil, payment_method_details: map() | nil, receipt_email: String.t() | nil, receipt_number: String.t() | nil, receipt_url: String.t() | nil, refunded: boolean() | nil, refunds: map() | nil, review: String.t() | nil, source_transfer: LatticeStripe.Transfer.t() | String.t() | nil, statement_descriptor: String.t() | nil, statement_descriptor_suffix: String.t() | nil, status: atom() | String.t() | nil, transfer_data: map() | nil, transfer_group: String.t() | nil }
A Stripe Charge object.
See the Stripe Charge API for field
definitions. Unknown fields are preserved in :extra (F-001).
Functions
@spec capture(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: {:ok, t()} | {:error, LatticeStripe.Error.t()}
Captures an uncaptured Charge.
Sends POST /v1/charges/:id/capture with optional params and returns
{:ok, %Charge{}}. Only applicable to Charges created via legacy direct-charge
flows that were not yet captured.
For charges created by PaymentIntent confirmation, use
LatticeStripe.PaymentIntent.capture/4 instead — capturing a PI-initiated charge
through this function is not the supported path.
Parameters
client- A%LatticeStripe.Client{}structid- The Charge ID stringparams- Optional capture params (e.g.,%{"amount" => 1500})opts- Per-request overrides
Returns
{:ok, %Charge{}}on success{:error, %LatticeStripe.Error{}}on failure
@spec capture!(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: t()
Like capture/4 but raises LatticeStripe.Error on failure.
Converts a decoded Stripe API map to a %Charge{} struct.
Maps every known Stripe Charge field explicitly. Any unrecognized fields
are collected into :extra (F-001) so no data is silently lost when Stripe
adds new fields.
from_map(nil) returns nil for use with optional/nullable charge payloads.
@spec list(LatticeStripe.Client.t(), map(), keyword()) :: {:ok, LatticeStripe.Response.t()} | {:error, LatticeStripe.Error.t()}
Lists Charges with optional filters.
Sends GET /v1/charges and returns {:ok, %Response{data: %List{}}} with
typed %Charge{} items.
Parameters
client- A%LatticeStripe.Client{}structparams- Filter params (e.g.,%{"limit" => "10", "customer" => "cus_123"})opts- Per-request overrides
Returns
{:ok, %Response{data: %List{data: [%Charge{}, ...]}}}on success{:error, %LatticeStripe.Error{}}on failure
Example
{:ok, resp} = LatticeStripe.Charge.list(client, %{"limit" => "20"})
Enum.each(resp.data.data, &IO.inspect/1)
@spec list!(LatticeStripe.Client.t(), map(), keyword()) :: LatticeStripe.Response.t()
Like list/3 but raises LatticeStripe.Error on failure.
@spec retrieve(LatticeStripe.Client.t(), String.t(), keyword()) :: {:ok, t()} | {:error, LatticeStripe.Error.t()}
Retrieves a Charge by ID.
Sends GET /v1/charges/:id and returns {:ok, %Charge{}}.
Raises ArgumentError (pre-network) if id is nil or an empty string.
Parameters
client- A%LatticeStripe.Client{}structid- The Charge ID string (e.g.,"ch_3OoLqrJ...")opts- Per-request overrides. Supportsexpand: ["balance_transaction", ...]to inline expanded child objects.
Returns
{:ok, %Charge{}}on success{:error, %LatticeStripe.Error{}}on failure
Example
{:ok, charge} =
LatticeStripe.Charge.retrieve(client, "ch_3OoLqrJ...",
expand: ["balance_transaction"]
)
application_fees =
charge.balance_transaction["fee_details"]
|> Enum.filter(fn fd -> fd["type"] == "application_fee" end)
@spec retrieve!(LatticeStripe.Client.t(), String.t(), keyword()) :: t()
Like retrieve/3 but returns the bare %Charge{} on success and raises
LatticeStripe.Error on failure.
Also raises ArgumentError (pre-network) when id is nil or empty.
@spec search(LatticeStripe.Client.t(), String.t(), keyword()) :: {:ok, LatticeStripe.Response.t()} | {:error, LatticeStripe.Error.t()}
Searches Charges using Stripe's search query language.
Sends GET /v1/charges/search with the query string and returns typed results.
Note: search results have eventual consistency — newly created Charges may not
appear immediately.
Parameters
client- A%LatticeStripe.Client{}structquery- Stripe search query string (e.g.,"status:'succeeded' AND currency:'usd'")opts- Per-request overrides
Returns
{:ok, %Response{data: %List{data: [%Charge{}, ...]}}}on success{:error, %LatticeStripe.Error{}}on failure
Example
{:ok, resp} = LatticeStripe.Charge.search(client, "status:'succeeded'")
@spec search!(LatticeStripe.Client.t(), String.t(), keyword()) :: LatticeStripe.Response.t()
Like search/3 but raises LatticeStripe.Error on failure.
@spec search_stream!(LatticeStripe.Client.t(), String.t(), keyword()) :: Enumerable.t()
Returns a lazy stream of all Charges matching the search query (auto-pagination).
Emits individual %Charge{} structs, fetching additional search pages as needed.
Raises LatticeStripe.Error if any page fetch fails.
Parameters
client- A%LatticeStripe.Client{}structquery- Stripe search query stringopts- Per-request overrides
Returns
An Enumerable.t() of %Charge{} structs.
@spec stream!(LatticeStripe.Client.t(), map(), keyword()) :: Enumerable.t()
Returns a lazy stream of all Charges matching the given params (auto-pagination).
Emits individual %Charge{} structs, fetching additional pages as needed.
Raises LatticeStripe.Error if any page fetch fails.
Parameters
client- A%LatticeStripe.Client{}structparams- Filter params (e.g.,%{"limit" => "100"})opts- Per-request overrides
Returns
An Enumerable.t() of %Charge{} structs.
Example
client
|> LatticeStripe.Charge.stream!()
|> Stream.take(500)
|> Enum.to_list()
@spec update(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: {:ok, t()} | {:error, LatticeStripe.Error.t()}
Updates a Charge by ID.
Sends POST /v1/charges/:id with the given params and returns {:ok, %Charge{}}.
Note: the Stripe API only supports updating the metadata and description
fields on a Charge.
Parameters
client- A%LatticeStripe.Client{}structid- The Charge ID stringparams- Map of fields to update (only"metadata"and"description"are accepted by Stripe)opts- Per-request overrides
Returns
{:ok, %Charge{}}on success{:error, %LatticeStripe.Error{}}on failure
@spec update!(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: t()
Like update/4 but raises LatticeStripe.Error on failure.