Stripe Connect lets platforms make API calls on behalf of connected accounts. This guide covers both direct API access and the OAuth onboarding flow.

Making Calls on Behalf of Connected Accounts

Pass stripe_account to set the Stripe-Account header, either on the client or per-request:

On the Client

All calls made with this client will target the connected account:

client = Stripe.client("sk_test_platform",
  stripe_account: "acct_connected_123"
)

{:ok, charge} = Stripe.Services.ChargeService.retrieve(client, "ch_123")
{:ok, customer} = Stripe.Services.CustomerService.list(client, %{"limit" => 10})

Per-Request

Override for a single call without changing the client:

client = Stripe.client("sk_test_platform")

{:ok, charge} = Stripe.Services.ChargeService.retrieve(client, "ch_123",
  stripe_account: "acct_connected_123"
)

OAuth Flow

Use Stripe.OAuth to onboard connected accounts via the OAuth authorization flow. This requires a client_id from your Connect settings.

1. Build the Authorization URL

Redirect the user to Stripe's authorization page:

client = Stripe.client("sk_test_...", client_id: "ca_...")

{:ok, url} = Stripe.OAuth.authorize_url(client, %{
  scope: "read_write",
  redirect_uri: "https://example.com/callback"
})

# Redirect the user to `url`

2. Exchange the Authorization Code

After the user authorizes, Stripe redirects back with a code parameter. Exchange it for access tokens:

{:ok, resp} = Stripe.OAuth.token(client, %{
  grant_type: "authorization_code",
  code: "ac_..."
})

# resp contains:
# - stripe_user_id: the connected account ID
# - access_token: for making API calls
# - refresh_token: for refreshing the access token

3. Deauthorize

Revoke access to a connected account:

{:ok, resp} = Stripe.OAuth.deauthorize(client, %{
  client_id: "ca_...",
  stripe_user_id: "acct_..."
})

Multi-Tenant Patterns

For platforms serving many connected accounts, create clients dynamically:

defmodule MyApp.Stripe do
  def client_for_account(account_id) do
    Stripe.client(platform_key(),
      stripe_account: account_id
    )
  end

  defp platform_key do
    Application.fetch_env!(:my_app, :stripe_secret_key)
  end
end

# Usage
client = MyApp.Stripe.client_for_account("acct_123")
{:ok, charges} = Stripe.Services.ChargeService.list(client, %{"limit" => 5})

Since clients are plain structs with no global state, this is safe for concurrent use across processes.