Authentication with Connect

Learn how to authenticate as your users, so you can perform any API actions on their behalf. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

API authentication

There are two ways of authenticating requests when performing actions on behalf of a connected account. Both approaches assume you previously stored information about the connected account for later use: the Stripe account ID and/or the account’s secret and publishable keys.

For most integrations, you should go with the first option—it’s easier and likely more secure. If you have any application that requires you to publish keys (e.g. a mobile app), you might want to use the second instead.

Authentication via the Stripe-Account header

The first, preferred, authentication option is to use your (the platform account’s) secret key and pass a Stripe-Account header identifying the connected account for which the request is being made. This code performs a refund of a charge on behalf of a connected account:

curl https://api.stripe.com/v1/charges/{CHARGE_ID}/refunds \
   -u {PLATFORM_SECRET_KEY}: \
   -H "Stripe-Account: {CONNECTED_STRIPE_ACCOUNT_ID}" \
   -d amount=1000

This authentication approach is implied in any API request that includes the Stripe account ID in the URL:

curl https://api.stripe.com/v1/accounts/{CONNECTED_STRIPE_ACCOUNT_ID} \
   -u {PLATFORM_SECRET_KEY}:

With this method, you only need to store a single secret key, which can be easier to secure than many keys.

All of Stripe’s libraries support this style of authentication on a per-request basis:

Stripe.api_key = PLATFORM_SECRET_KEY
Stripe::Customer.create(
  {:description => "example@stripe.com"},
  {:stripe_account => CONNECTED_STRIPE_ACCOUNT_ID}
)

# Fetching an account just needs the ID as a parameter
Stripe::Account.retrieve(CONNECTED_STRIPE_ACCOUNT_ID)
stripe.api_key = PLATFORM_SECRET_KEY
stripe.Customer.create(
  description="example@stripe.com",
  stripe_account=CONNECTED_STRIPE_ACCOUNT_ID
)

# Fetching an account just needs the ID as a parameter
stripe.Account.retrieve(CONNECTED_STRIPE_ACCOUNT_ID)
\Stripe\Stripe::setApiKey(PLATFORM_SECRET_KEY);
\Stripe\Customer::create(
  array("description" => "example@stripe.com"),
  array("stripe_account" => CONNECTED_STRIPE_ACCOUNT_ID)
);

// Fetching an account just needs the ID as a parameter
\Stripe\Account::retrieve(CONNECTED_STRIPE_ACCOUNT_ID);
Stripe.apiKey = PLATFORM_SECRET_KEY;
RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(CONNECTED_STRIPE_ACCOUNT_ID).build();

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("description", "example@stripe.com");

Customer.create(customerParams, requestOptions);

// Fetching an account just needs the ID as a parameter
Account.retrieve(CONNECTED_STRIPE_ACCOUNT_ID);
var stripe = require('stripe')(PLATFORM_SECRET_KEY);
stripe.customers.create(
  {description: "example@stripe.com"},
  {stripe_account: CONNECTED_STRIPE_ACCOUNT_ID}
);

// Fetching an account just needs the ID as a parameter
stripe.accounts.retrieve(CONNECTED_STRIPE_ACCOUNT_ID);

Authentication via API keys

The second authentication option uses the connected account’s secret and publishable keys instead. Here is the same refund request as above performed using this second authentication method:

curl https://api.stripe.com/v1/charges/{CHARGE_ID}/refunds \
   -u {CONNECTED_ACCOUNT_SECRET_KEY}: \
   -d amount=1000

The connected account’s secret key can either be provided by the account creation’s API call under keys[secret], or an access_token, provided by the OAuth flow.

You’d only want to use this authentication method if you intend to make the key accessible to the account holder. For example, if you created a mobile application that talks directly to Stripe, you would not want to store your secret key in the application (as then any user would be able to extract your key and use it to access any other user’s account). Instead you should send the account-specific secret key to the application, as it only allows access to the account holder’s account.

If you are using this method, we recommend that you perform authentication with every request, instead of setting the API key globally.

# Not recommended: setting global API key state
Stripe.api_key = CONNECTED_ACCOUNT_SECRET_KEY
Stripe::Customer.create(
  :description => "example@stripe.com"
)

# Recommended: sending API key with every request
Stripe::Customer.create(
  {:description => "example@stripe.com"},
  :api_key => CONNECTED_ACCOUNT_SECRET_KEY # account's access token from the Connect flow
)
# Not recommended: setting global API key state
stripe.api_key = CONNECTED_ACCOUNT_SECRET_KEY
stripe.Customer.create(
  description="example@stripe.com"
)

# Recommended: sending API key with every request
stripe.Customer.create(
  description="example@stripe.com",
  api_key=CONNECTED_ACCOUNT_SECRET_KEY # account's access token from the Connect flow
)
// Not recommended: setting global API key state
\Stripe\Stripe::setApiKey(CONNECTED_ACCOUNT_SECRET_KEY);
\Stripe\Customer::create(
  array("description" => "example@stripe.com")
);

// Recommended: sending API key with every request
\Stripe\Customer::create(
  array("description" => "example@stripe.com"),
  array("api_key" => CONNECTED_ACCOUNT_SECRET_KEY) // account's access token from the Connect flow
);
// Not recommended: setting global API key state
Stripe.apiKey = CONNECTED_ACCOUNT_SECRET_KEY;

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("description", "example@stripe.com");

Customer.create(customerParams);

// Recommended: sending API key with every request
RequestOptions requestOptions = RequestOptions.builder().setApiKey(CONNECTED_ACCOUNT_SECRET_KEY).build();

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("description", "example@stripe.com");

Customer.create(customerParams, requestOptions);
// Not recommended: setting global API key state
var stripe = require('stripe')(CONNECTED_ACCOUNT_SECRET_KEY);
stripe.customers.create({
  description: "example@stripe.com"
});

// Recommended: sending API key with every request
stripe.customers.create(
  { description: "example@stripe.com" },
  { api_key: CONNECTED_ACCOUNT_SECRET_KEY } // account's access token from the Connect flow
);

Webhooks

You’ll use webhooks to be notified about events that happen in a Stripe account. Your webhook URLs, which receive the event notifications, are configured in your webhook settings.

Note that there are two types of webhooks:

  • Account webhooks are for activity on your own account (e.g., most requests made using your API keys and without authenticating as another Stripe account).
  • Connect webhooks are for activity on any connected account. This includes the important account.updated event for any connected accounts.

For Connect webhooks, it’s important to note that while only test webhooks will be sent to your development webhook URLs, both live and test webhooks will be sent to your production webhook URLs. This is due to the fact that you can perform both live and test transactions under a production application. For this reason, we recommend you check the livemode value when receiving an event webhook to know what action, if any, should be taken.

In addition to the documented response properties in the event object reference, each event for a connected account will also contain a top-level user_id property. It identifies the user for whom the webhook is being sent.

{
  "id": "evt_XvuISBQArfpwFh",
  "livemode": true,
  "object": "event",
  "type": "customer.created",
  "user_id": "acct_QVO4XcUfxUlCGd",
  "pending_webhooks": 2,
  "created": 1349654313,
  "data": {...}
}

For more information about webhooks, see the webhook documentation or event object reference.

After authenticating

Check out the rest of the guide to learn how to perform actions on behalf of your users.