LatticeStripe.Account (LatticeStripe v1.1.0)

Copy Markdown View Source

Operations on Stripe Connect Account objects.

A Connect Account represents a user's connected Stripe account that your platform transacts on behalf of. Phase 17 delivers the full account lifecycle (create/3, retrieve/3, update/4, delete/3, reject/4, list/3, stream!/3) plus the companion onboarding URL modules LatticeStripe.AccountLink and LatticeStripe.LoginLink.

Acting on behalf of a connected account

LatticeStripe already threads the Stripe-Account header end-to-end in LatticeStripe.Client. You can set a connected account either per-client OR per-request:

# Per-client (platform holds the key, acts on one connected account)
client = LatticeStripe.Client.new!(
  api_key: "sk_test_platform",
  finch: MyApp.Finch,
  stripe_account: "acct_connected"
)
LatticeStripe.Customer.create(client, %{email: "c@example.test"})

# Per-request (platform holds the key, switches connected account per-call)
LatticeStripe.Customer.create(client, %{email: "c@example.test"},
  stripe_account: "acct_connected")

The per-request opt takes precedence over the per-client value. See the Connect guide for idiomatic patterns.

D-01 nested struct budget reframing

Phase 17 amends Phase 16's D1 nested-struct budget rule: the 5-module budget now counts DISTINCT nested struct modules, not promoted parent fields. This resource exercises the reframing — LatticeStripe.Account.Requirements is defined once and reused at both %Account{}.requirements and %Account{}.future_requirements. Subsequent phases should treat the rule as "up to 5 distinct nested struct modules per resource, with reuse encouraged."

Requesting capabilities

LatticeStripe does NOT provide a request_capability/4 helper (rejected per Phase 17 D-04b as fake ergonomics — the capability name set is an open, growing string enum). Use update/4 with the nested map idiom:

LatticeStripe.Account.update(client, "acct_123", %{
  capabilities: %{
    "card_payments" => %{requested: true},
    "transfers" => %{requested: true}
  }
})

Rejecting a connected account

reject/4 calls POST /v1/accounts/:id/reject with a single reason atom. The reason is guarded at the function head:

LatticeStripe.Account.reject(client, "acct_123", :fraud)
LatticeStripe.Account.reject(client, "acct_123", :terms_of_service)
LatticeStripe.Account.reject(client, "acct_123", :other)

Any other atom raises FunctionClauseError at call time. This is an irreversible action — once rejected, the connected account cannot accept charges or transfers. Wire account.application.deauthorized and account.updated webhooks in LatticeStripe.Webhook rather than driving state from the SDK response.

Webhook handoff

Drive your application state from webhook events, not SDK responses. An SDK response reflects the account state at the moment of the call, but Stripe may transition the account a moment later (capability activation, requirements update, payouts enablement). Wire account.updated, account.application.authorized, and account.application.deauthorized into your webhook handler.

Stripe API Reference

See the Stripe Accounts API.

Summary

Types

t()

A Stripe Connect Account object.

Functions

Creates a new Connect Account.

Deletes a Connect Account.

Like delete/3 but raises on failure.

Lists Connect Accounts with optional filters.

Like list/3 but raises on failure.

Rejects a Connect account.

Retrieves a Connect Account by ID.

Like retrieve/3 but raises on failure.

Returns a lazy stream of all Connect Accounts matching the given params.

Updates a Connect Account by ID.

Types

t()

@type t() :: %LatticeStripe.Account{
  business_profile: LatticeStripe.Account.BusinessProfile.t() | nil,
  business_type: String.t() | nil,
  capabilities:
    %{optional(String.t()) => LatticeStripe.Account.Capability.t()} | nil,
  charges_enabled: boolean() | nil,
  company: LatticeStripe.Account.Company.t() | nil,
  controller: map() | nil,
  country: String.t() | nil,
  created: integer() | nil,
  default_currency: String.t() | nil,
  details_submitted: boolean() | nil,
  email: String.t() | nil,
  external_accounts: map() | nil,
  extra: map(),
  future_requirements: LatticeStripe.Account.Requirements.t() | nil,
  id: String.t() | nil,
  individual: LatticeStripe.Account.Individual.t() | nil,
  livemode: boolean() | nil,
  metadata: map() | nil,
  object: String.t(),
  payouts_enabled: boolean() | nil,
  requirements: LatticeStripe.Account.Requirements.t() | nil,
  settings: LatticeStripe.Account.Settings.t() | nil,
  tos_acceptance: LatticeStripe.Account.TosAcceptance.t() | nil,
  type: String.t() | nil
}

A Stripe Connect Account object.

Functions

create(client, params \\ %{}, opts \\ [])

@spec create(LatticeStripe.Client.t(), map(), keyword()) ::
  {:ok, t()} | {:error, LatticeStripe.Error.t()}

Creates a new Connect Account.

Sends POST /v1/accounts.

Parameters

  • client - %LatticeStripe.Client{}
  • params - Map of account attributes. Common keys:
    • "type" - Account type: "custom", "express", or "standard"
    • "country" - Two-letter country code (e.g., "US")
    • "email" - Account email address
  • opts - Per-request overrides (e.g., [idempotency_key: "..."])

Returns

  • {:ok, %Account{}} on success
  • {:error, %LatticeStripe.Error{}} on failure

create!(client, params \\ %{}, opts \\ [])

@spec create!(LatticeStripe.Client.t(), map(), keyword()) :: t()

Like create/3 but raises on failure.

delete(client, id, opts \\ [])

@spec delete(LatticeStripe.Client.t(), String.t(), keyword()) ::
  {:ok, t()} | {:error, LatticeStripe.Error.t()}

Deletes a Connect Account.

Sends DELETE /v1/accounts/:id. Stripe returns a deletion stub %{"id" => ..., "object" => "account", "deleted" => true}. The returned %Account{} will have extra: %{"deleted" => true}.

Irreversible

Deletion cannot be undone. Only custom and express accounts may be deleted; standard accounts must be rejected via reject/4 instead.

delete!(client, id, opts \\ [])

@spec delete!(LatticeStripe.Client.t(), String.t(), keyword()) :: t()

Like delete/3 but raises on failure.

list(client, params \\ %{}, opts \\ [])

@spec list(LatticeStripe.Client.t(), map(), keyword()) ::
  {:ok, LatticeStripe.Response.t()} | {:error, LatticeStripe.Error.t()}

Lists Connect Accounts with optional filters.

Sends GET /v1/accounts.

list!(client, params \\ %{}, opts \\ [])

Like list/3 but raises on failure.

reject(client, id, reason, opts \\ [])

@spec reject(
  LatticeStripe.Client.t(),
  String.t(),
  :fraud | :terms_of_service | :other,
  keyword()
) ::
  {:ok, t()} | {:error, LatticeStripe.Error.t()}

Rejects a Connect account.

Dispatches to POST /v1/accounts/:id/reject with the atom reason converted to its Stripe string form. The reason MUST be one of :fraud, :terms_of_service, or :other — any other atom raises FunctionClauseError at the call site.

Example

Account.reject(client, "acct_123", :fraud)

Irreversibility

Rejection is one-way. Once rejected, the connected account cannot be re-activated. This is why reject/4 guards the reason at the function head — a typo like :fruad fails loudly at compile-time (for literal atoms) or runtime, rather than silently sending an invalid payload to Stripe.

reject!(client, id, reason, opts \\ [])

@spec reject!(
  LatticeStripe.Client.t(),
  String.t(),
  :fraud | :terms_of_service | :other,
  keyword()
) ::
  t()

Like reject/4 but raises on failure.

retrieve(client, id, opts \\ [])

@spec retrieve(LatticeStripe.Client.t(), String.t(), keyword()) ::
  {:ok, t()} | {:error, LatticeStripe.Error.t()}

Retrieves a Connect Account by ID.

Sends GET /v1/accounts/:id.

retrieve!(client, id, opts \\ [])

@spec retrieve!(LatticeStripe.Client.t(), String.t(), keyword()) :: t()

Like retrieve/3 but raises on failure.

stream!(client, params \\ %{}, opts \\ [])

@spec stream!(LatticeStripe.Client.t(), map(), keyword()) :: Enumerable.t()

Returns a lazy stream of all Connect Accounts matching the given params.

Auto-paginates via LatticeStripe.List.stream!/2. Raises on fetch failure.

update(client, id, params, opts \\ [])

@spec update(LatticeStripe.Client.t(), String.t(), map(), keyword()) ::
  {:ok, t()} | {:error, LatticeStripe.Error.t()}

Updates a Connect Account by ID.

Sends POST /v1/accounts/:id.

To request capabilities, use the nested map idiom — do not look for a request_capability/4 helper, which does not exist (D-04b). See the "Requesting capabilities" section in the module doc.

update!(client, id, params, opts \\ [])

@spec update!(LatticeStripe.Client.t(), String.t(), map(), keyword()) :: t()

Like update/4 but raises on failure.