Connecting to Standalone Accounts

    Integrating with standalone Stripe accounts is the fastest and easiest way to get started, since you'll be offloading the majority of the user experience and user communication to Stripe. If you need help after reading this, search our documentation or check out answers to common questions. You can even chat live with other developers in #stripe on freenode.

    A standalone Stripe account is a normal Stripe account that is controlled by the account holder: your platform’s user. (By contrast, managed accounts are fully controlled by the platform.)

    To connect to Standalone Accounts—either if your users already have accounts or if you’d like them to create accounts—you’ll want to integrate with our standard OAuth flow. With this flow, there’s minimal integration work to do in terms of onboarding, communicating with users, ongoing maintenance, and so on since Stripe handles all of it for you and your users will have access to the Dashboard. (Of course, this also means that there’s not as much user experience customizability.)

    Unless you’re looking to fully control the user experience from the beginning, we recommend starting off with an OAuth integration.

    What does the flow look like?

    When a user wants to connect to your platform, they’ll go through these steps:

    1. Starting on a page at your site, the user will click a link that takes them to Stripe, passing along your platform’s client_id.
    2. On Stripe’s website, the user will be prompted to connect their Stripe account, or create a new account if they don’t already have one.
    3. The user will then be redirected back to your site (specifically to your redirect_uri), passing along either an authorization code or an error (if the connection request was denied).
    4. Your site then makes a request to our OAuth token endpoint to fetch the user’s authorization credentials, storing them on your site.
    5. Subsequent API requests can be made on behalf of the connected account using the authorization credentials.

    Unlike most OAuth implementations (like Facebook Connect or Sign In with Twitter), we’ve seamlessly added the process of creating a Stripe account right into our authorization flow. You don’t have to worry about whether or not your users already have Stripe accounts.

    The user is logged in, and can connect directly.

    The user needs to create an account.

    When your users land back on your site, their account is ready to accept credit card payments. You can also retrieve their account status at any time.

    Keep reading for a step-by-step guide to integrating the flow. You can also check out the OAuth reference for additional details on the request and response parameters.

    Integrating OAuth

    To get started with your integration, you’ll first need to know two key pieces of information from in your platform settings:

    • Your client_id, a unique identifier for your platform, generated by Stripe.
    • Your redirect_uri, a page on your website to which the user will be redirected after connecting their account (or failing to, should that be the case), set by you.

    Stripe also provides a development client_id, to make testing easier.

    Connecting users

    With these two pieces of information in hand, you’re ready to have your users connect with your platform. We recommend showing a Connect button that sends them to our authorize_url endpoint:

    The Stripe endpoint needs to at least receive two parameters:

    • response_type, with a value of code.
    • Your client_id.

    You’ll likely also want to provide the scope. This parameter dictates what your platform will be able to do on behalf of the connected account. The options are read_write and read_only, with read_only being the default.

    For an analytics platform, read_only is appropriate; if you need to perform charges on behalf of the connected user, you will need to request read_write scope instead. See the OAuth reference for more.

    Here is how this may look (the href value matches that above):

    Connect with Stripe

    After the user has connected

    When the user arrives at Stripe, they’ll be prompted to allow or deny the connection to your platform, and will then be sent to your redirect_uri page. In the URL, we’ll pass along an authorization code:

    If the authorization was denied by the user, we’ll include an error instead:

    Using the code parameter, you should make a POST request to our access_token_url endpoint (also see the sample-code below for non-curl examples):

    curl \
       -d client_secret=sk_test_BQokikJOvBiI2HlWgH4olfQ2 \
       -d code=AUTHORIZATION_CODE \
       -d grant_type=authorization_code

    Note that you’ll make the request with your live secret API key or test secret API key, depending on whether you want to get a live or test access token back.

    Stripe will return a response containing the authentication credentials for the user:

      "token_type": "bearer",
      "stripe_publishable_key": PUBLISHABLE_KEY,
      "scope": "read_write",
      "livemode": false,
      "stripe_user_id": USER_ID,
      "refresh_token": REFRESH_TOKEN,
      "access_token": ACCESS_TOKEN

    If there was a problem, we’ll instead return an error:

      "error": "invalid_grant",
      "error_description": "Authorization code does not exist: AUTHORIZATION_CODE"

    You’re done! The user is now connected to your platform. You can store the stripe_user_id in your database and use this value to authenticate as the connected account by passing it into requests in the Stripe-Account header. It’s also possible to authenticate with the secret key returned here, but it’s more secure to store and use only the account ID instead.

    You’ll notice that the response also includes a refresh_token. This can be used to generate test access tokens for a production client_id or to roll your access token. You should hold on to this, as you’re only able to get it after this initial POST request.

    Customizing the user experience

    Through additional parameters you can supply Stripe, you can easily customize the user’s experience. Below are a few example uses of those parameters, but see the OAuth reference for the full list.

    Pre-filling fields

    If your user needs to set up a new account with Stripe, you can provide the best possible user experience by pre-filling the account form fields with information you already have, like the user’s email and name. Pre-filling has no effect if your user already has an existing Stripe account.

    Alternatively, if you know your user has a Stripe account already, you can use the stripe_landing parameter, with a value of login, to have Stripe show a login screen instead of the default account application.

    Dynamically setting the redirect URI

    For security purposes, Stripe will only redirect a user to a pre-defined url. However, Connect allows you to define more than one redirect URI, which can be used to further customize the user’s experience. For example, you could have some of your users redirected back to and others sent to, each with custom behavior.

    First, in your platform settings, set the redirect URIs to a comma-separated list of allowed URIs. Second, add a redirect_uri parameter to your authorization request with a value found in your comma-separated list.

    The first URI in your comma-separated list will always be treated as the default.

    Deferred account activation

    In some cases, you may want to defer account activation until later—that is, let your user start accepting payments without completely setting up their account.

    To do this, you can spin up a standalone account with just a country and email address.

    Revoked Access

    An account.application.deauthorized webhook event is sent when a user disconnects your platform from their account. By watching for this event, you can perform any necessary credential cleanup on your servers. (Note that a managed account cannot be disconnected by the account’s beneficiary.)

    Additionally, if you want to disconnect access to a standalone account (for example, to stop getting webhooks for an account you no longer work with), you can POST your client_id and the connected account’s ID to

    curl \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d client_id=ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7 \
       -d stripe_user_id=acct_SbSdOydDf1u1o2
    # Using stripe-ruby
    acct = Stripe::Account.retrieve("acct_UvdGjX8QZZSb4z")
    # Using rest-client:
        client_id: 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7',
        stripe_user_id: 'acct_smY2DErB4ZG1fw',
      {Authorization: 'Bearer sk_test_BQokikJOvBiI2HlWgH4olfQ2'}
    # Using requests:
        'client_id': 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7',
        'stripe_user_id': 'acct_ME4XMtzfOem1Cq',
      headers={'Authorization': 'Bearer sk_test_BQokikJOvBiI2HlWgH4olfQ2'}
    // Using curl:
    $api_key = 'sk_test_BQokikJOvBiI2HlWgH4olfQ2';
    $curl = curl_init();
    curl_setopt_array($curl, array(
      CURLOPT_URL => '',
      CURLOPT_HTTPHEADER => array("Authorization: Bearer $api_key"),
      CURLOPT_POST => true,
      CURLOPT_POSTFIELDS => http_build_query(array(
        'client_id' => 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7',
        'stripe_user_id' => 'acct_pua2eYmfN0ayED',
    // Using Apache HttpComponents:
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost("");
    httpPost.setHeader("Authorization", "Bearer sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    List <NameValuePair> nvps = new ArrayList <NameValuePair>();
    nvps.add(new BasicNameValuePair("client_id", "ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7"));
    nvps.add(new BasicNameValuePair("stripe_user_id", "acct_8RJ9PhvlnMDAdh"));
    httpPost.setEntity(new UrlEncodedFormEntity(nvps));
    CloseableHttpResponse response = httpclient.execute(httpPost);
    // Using request:
    var request = require('request');{
      url: '',
      formData: {
        client_id: 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7',
        stripe_user_id: 'acct_E2vyzakDODpzkM',
      headers: {'Authorization': 'Bearer sk_test_BQokikJOvBiI2HlWgH4olfQ2'},
    // Using "net/http":
    client := &http.Client{}
    req, err := http.NewRequest("POST",
            "client_id": {"ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7"},
            "stripe_user_id": {"acct_SJ3RIKKz2lvA1M"}
    req.Header.Add("Authorization", "Bearer sk_test_BQokikJOvBiI2HlWgH4olfQ2")
    resp, err := client.Do(req)

    Sample OAuth Applications

    Here’s some sample code for performing the OAuth flow, but we recommend that you use a client library instead of handling the implementation yourself.

    # See full code example here:
    # Using OAuth2 gem by Intridea (
    # Additionally, check out this OmniAuth Stripe Connect gem:
    configure do
      config = YAML::load('config.yml'))
      set :api_key, config['api_key']
      set :client_id, config['client_id']
      options = {
        :site => '',
        :authorize_url => '/oauth/authorize',
        :token_url => '/oauth/token'
      set :client,, settings.api_key, options)
    get '/authorize' do
      params = {
        :scope => 'read_write'
      # Redirect the user to the authorize_uri endpoint
      url = settings.client.auth_code.authorize_url(params)
      redirect url
    get '/oauth/callback' do
      # Pull the authorization_code out of the response
      code = params[:code]
      # Make a request to the access_token_uri endpoint to get an access_token
      @resp = settings.client.auth_code.get_token(code, :params => {:scope => 'read_write'})
      @access_token = @resp.token
      # Use the access_token as you would a regular live-mode API key
      # TODO: Stripe logic
      erb :callback
    # See full code example here:
    def authorize:
      site = app.config['SITE'] + app.config['AUTHORIZE_URI']
      params = {
        "response_type": "code",
        "scope": "read_write",
        "client_id": app.config['CLIENT_ID']
      # Redirect to Stripe /oauth/authorize endpoint
      url = site + '?' + urllib.urlencode(params)
      return redirect(url)
    def callback:
      code = request.args.get('code')
      data = {
        "grant_type": "authorization_code",
        "client_id": app.config['CLIENT_ID'],
        "client_secret": app.config['API_KEY']
        "code": code
      # Make /oauth/token endpoint POST request
      url = app.config['SITE'] + app.config['TOKEN_URI']
      resp =, params=data)
      # Grab access_token (use this as your user's API key)
      token = resp.json().get('access_token')
      return render_template('callback.html', token=token)
    // See full code example here:
    if (isset($_GET['code'])) { // Redirect w/ code
      $code = $_GET['code'];
      $token_request_body = array(
        'grant_type' => 'authorization_code',
        'client_id' => 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7',
        'code' => $code,
        'client_secret' => 'sk_test_BQokikJOvBiI2HlWgH4olfQ2'
      $req = curl_init(TOKEN_URI);
      curl_setopt($req, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($req, CURLOPT_POST, true );
      curl_setopt($req, CURLOPT_POSTFIELDS, http_build_query($token_request_body));
      // TODO: Additional error handling
      $respCode = curl_getinfo($req, CURLINFO_HTTP_CODE);
      $resp = json_decode(curl_exec($req), true);
      echo $resp['access_token'];
    } else if (isset($_GET['error'])) { // Error
      echo $_GET['error_description'];
    } else { // Show OAuth link
      $authorize_request_body = array(
        'response_type' => 'code',
        'scope' => 'read_write',
        'client_id' => 'ca_32D88BD1qLklliziD7gYQvctJIhWBSQ7'
      $url = AUTHORIZE_URI . '?' . http_build_query($authorize_request_body);
      echo "<a href='$url'>Connect with Stripe</a>";
    // See full code example here:
    // Using Spark framework (
    get(new Route("/authorize") {
        public Object handle(Request request, Response response) {
            URI uri = new URIBuilder(AUTHORIZE_URI)
                    .setParameter("response_type", "code")
                    .setParameter("scope", "read_write")
                    .setParameter("client_id", CLIENT_ID)
            // Redirect to Stripe /oauth/authorize endpoint
            return "";
    get(new FreeMarkerRoute("/oauth/callback") {
        public ModelAndView handle(Request request, Response response) {
            Map<String, Object> viewObjects = new HashMap<String, Object>();
            CloseableHttpClient httpClient = HttpClients.createDefault();
            String code = request.queryParams("code");
            URI uri = new URIBuilder(TOKEN_URI)
                    .setParameter("client_secret", API_KEY)
                    .setParameter("grant_type", "authorization_code")
                    .setParameter("client_id", CLIENT_ID)
                    .setParameter("code", code)
            // Make /oauth/token endpoint POST request
            HttpPost httpPost = new HttpPost(uri);
            CloseableHttpResponse resp = httpClient.execute(httpPost);
            // Grab access_token (use this as your user's API key)
            String bodyAsString = EntityUtils.toString(resp.getEntity());
            Type t = new TypeToken<Map<String, String>>() { }.getType();
            Map<String, String> map = new GsonBuilder().create().fromJson(bodyAsString, t);
            String token = map.get("access_token");
            viewObjects.put("token", token);
            return modelAndView(viewObjects, "callback.ftl");
    // See full code example here:
    app.get("/authorize", function(req, res) {
      // Redirect to Stripe /oauth/authorize endpoint
      res.redirect(AUTHORIZE_URI + "?" + qs.stringify({
        response_type: "code",
        scope: "read_write",
        client_id: CLIENT_ID
    app.get("/oauth/callback", function(req, res) {
      var code = req.query.code;
      // Make /oauth/token endpoint POST request{
        url: TOKEN_URI,
        form: {
          grant_type: "authorization_code",
          client_id: CLIENT_ID,
          code: code,
          client_secret: API_KEY
      }, function(err, r, body) {
        var accessToken = JSON.parse(body).access_token;
        // Do something with your accessToken
        // For demo"s sake, output in response:
        res.send({ "Your Token": accessToken });

    You're connected!

    Now you can use the API on your user's behalf to accept payments, set up recurring billing, fetch account data, and more.