Using Account Tokens

    Connect platforms can use Stripe.js to securely collect account details for its connected users.

    To fulfill “Know Your Customer” (KYC) requirements, Stripe must verify information about its users, including information about users on Connect platforms. Account tokens provide a secure and reliable way to perform this task. Account tokens also allow Stripe to more accurately detect potential fraud.

    Account tokens can only be used for:

    • Legal entity details
    • Indicating acceptance of the Stripe Connected Account Agreement

    Account tokens cannot be used for any other account information, including:

    • Payout schedules
    • Payout destinations (e.g., a bank account)
    • The country of the connected account

    Account tokens are created using Stripe.js, and the process is effectively the same as tokenizing payment details or external accounts. The connected user’s information is sent directly to Stripe and exchanged for a representative token that can be used in a create account or update account call.

    Creating and using account tokens

    As with other uses of Stripe.js, account tokens require both client-side and server-side code:

    1. Create the HTML form that takes the user’s input.
    2. Add JavaScript that sends the form data to Stripe, receives a token in return, and submits that token to your server.
    3. Use the token in a server-side Stripe API call.

    However, unlike when tokenizing payment details, it’s fine if the submitted data also reaches your server. The critical feature of account tokens is transferring information directly from your user to Stripe.

    Step 1: Create the HTML form

    The first step is to create an HTML form that collects the requisite information. This includes any field found in the legal entity hash, plus acceptance of the Stripe Connected Account Agreement.

    Create form elements for the user’s information, such as name, address, and anything else required for legal entity verification in the user’s country.

    <form class="my-form" action="/create-account" method="post">
      <input type="hidden" name="token" id="token">
      <label>
        <span>First Name</span>
        <input class="inp-first-name" name="first_name">
      </label>
      <label>
        <span>Last Name</span>
        <input class="inp-last-name" name="last_name">
      </label>
      <fieldset>
    See all 31 lines <legend>Address</legend> <label> <span>Street Address Line 1</span> <input class="inp-street-address1" name="street_address1"> </label> <label> <span>City</span> <input class="inp-city" name="city"> </label> <label> <span>State</span> <input class="inp-state" name="state"> </label> <label> <span>Postal Code</span> <input class="inp-zip" name="zip"> </label> </fieldset> <button>Submit</button> </form>

    Presenting the Stripe Connected Account Agreement

    Platforms must make clear to its users that processing of payments is provided subject to the Stripe Connected Account Agreement. Indicating acceptance of the Stripe Connected Account Agreement is required when using an account token to create a new connected account.

    We recommend you include language like the following, including links to both our agreement and your terms of service.

    <p>By clicking, you agree to <a href="#">our terms</a> and the <a href="/connect-account/legal">Stripe Connected Account Agreement</a>.</p>
    <p>En cliquant sur ce bouton, vous acceptez <a href="#">nos Conditions Générales d'Utilisation</a> ainsi que les <a href="/connect-account/legal">Conditions d'Utilisation des Comptes Connectés Stripe</a></p>

    Step 2: Add JavaScript

    Next, the page needs JavaScript that:

    1. Interrupts the form submission.
    2. Calls the stripe.createToken() method to request a token.
    3. Sends the ID of the received token to your server.

    For simplicity, data validation and error handling are omitted in the below code, but remember to add both to your actual integration.

    Provide to the stripe.createToken() method two arguments:

    • The value account, to specifically request an account token
    • A generic object of information

    The JavaScript object needs a top-level legal_entity property that parallels the structure of the legal entity hash. Follow the legal entity hash structure through all sub-properties: for example, line1 within address is provided as legal_entity.address.line1.

    To represent the user’s acceptance of the Stripe Connected Account Agreement, provide a top-level tos_shown_and_accepted property with a value of true.

    Tokens must still be used—to create or update an account—via server-side code. You can send the token ID to your server using whatever approach makes sense for your application (e.g., an XHR request). For simplicity, the below code stores the token ID in a hidden form input and then submits the form.

    // Assumes you've already included Stripe.js!
    const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
    const myForm = document.querySelector('.my-form');
    myForm.addEventListener('submit', handleForm);
    
    async function handleForm(event) {
      event.preventDefault();
    
      const result = await stripe.createToken('account', {
        legal_entity: {
          first_name: document.querySelector('.inp-first-name').value,
          last_name: document.querySelector('.inp-last-name').value,
          address: {
            line1: document.querySelector('.inp-street-address1').value,
            city: document.querySelector('.inp-city').value,
            state: document.querySelector('.inp-state').value,
            postal_code: document.querySelector('.inp-zip').value,
          },
        },
        tos_shown_and_accepted: true,
      });
    
      if (result.token) {
        document.querySelector('#token').value = result.token.id;
        myForm.submit();
      }
    }
    

    Step 3: Use the token

    Upon successfully receiving an account token from Stripe, the above JavaScript stores the token ID in a hidden form input and then submits the form (to your server). The final step is for your server-side code to use the received token in a create account API call. Provide the token ID as the value for the account_token parameter.

    curl https://api.stripe.com/v1/accounts \
       -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
       -d country=US \
       -d type=custom \
       -d account_token=tok_GcbCQ1lBFIx9RUe7YiEtiWfq
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token = params[:token]
    acct = Stripe::Account.create({
        :country => "US",
        :type => "custom",
        :account_token => token,
    })
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token = request.form['token'] # Using Flask
    acct = stripe.Account.create(
      country="US",
      type="custom",
      account_token=token,
    )
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    $token = $_POST['token'];
    $acct = \Stripe\Account::create(array(
        "country" => "US",
        "type" => "custom",
        "account_token" => $token,
    ));
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc";
    
    String token = request.getParameter("token");
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("country", "US");
    params.put("type", "custom");
    params.put("account_token", "token");
    Account acct = Account.create(params);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var token = request.body.token; // Using Express
    stripe.accounts.create({
      country: "US",
      type: "custom",
      account_token: token,
    }).then(function(acct) {
      // asynchronously called
    });
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token := r.FormValue("stripeToken")
    params := &stripe.AccountParams{
      Country: stripe.String("US"),
      Type: stripe.String(string(stripe.AccountTypeCustom)),
      AccountToken: stripe.String(token),
    }
    acct, err := account.New(params)
    

    The date, ip, and user_agent attributes of the Account object’s tos_acceptance attribute are automatically populated by setting tos_shown_and_accepted to true in the token creation. (In a normal create account call not involving an account token, values for these must be specifically provided.)

    Handling a file upload

    When a connected user needs to provide Stripe with a scan of an identity document (e.g., a passport), this can also be done through an account token. However, the JavaScript required is a bit more complicated as the file must be sent to Stripe via an XHR request. In this flow, the JavaScript:

    1. Interrupts the form submission.
    2. If a file was uploaded, sends that to Stripe, receiving a file token in return.
    3. Adds the file token ID to the generic object for the account token request.
    4. Calls the stripe.createToken() method to request a token.
    5. Sends the ID of the received account token to your server for use.

    To begin, add a file element to the form. The uploaded file needs to be a color image (smaller than 8,000px by 8,000px), in JPG or PNG format, and less than 5MB in size.

    <input type="file" id="id-file" name="id-file" accept=".jpeg,.jpg,.png">

    Next, in your JavaScript that handles the form’s submission, send the uploaded file to Stripe. This needs to happen before creating the account token.

    const data = new FormData();
    data.append('file', document.querySelector('#id-file').files[0]);
    data.append('purpose', 'identity_document');
    const fileResult = await fetch('https://uploads.stripe.com/v1/files', {
      method: 'POST',
      headers: {'Authorization': `Bearer ${stripe._apiKey}`},
      body: data,
    });
    const fileData = await fileResult.json();
    

    Finally, include the returned file ID as the legal_entity.verification.document value in the generic object provided to the createToken() call:

    const result = await stripe.createToken('account', {
      legal_entity: {
        first_name: document.querySelector('.inp-first-name').value,
        last_name: document.querySelector('.inp-last-name').value,
        address: {
          line1: document.querySelector('.inp-street-address1').value,
          city: document.querySelector('.inp-city').value,
          state: document.querySelector('.inp-state').value,
          postal_code: document.querySelector('.inp-zip').value,
        },
        verification: {
          document: fileData.id,
        },
      },
      tos_shown_and_accepted: true,
    });
    

    Updating legal entity details

    Account tokens can be used to securely update an existing account’s legal entity information as well. Simply create the token using the same combination of HTML and JavaScript as above, and then perform an update account call providing the new account token ID for the account_token parameter.

    Note that you must create and provide a new account token when updating legal entity details previously set via an account token.

    curl https://api.stripe.com/v1/accounts/{CONNECTED_STRIPE_ACCOUNT_ID} \
       -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
       -d account_token=tok_GcbCQ1lBFIx9RUe7YiEtiWfq
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    Stripe.api_key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token = params[:token]
    acct = Stripe::Account.retrieve({CONNECTED_STRIPE_ACCOUNT_ID})
    acct.account_token = token
    acct.save
    
    # Set your secret key: remember to change this to your live secret key in production
    # See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.api_key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token = request.form['token'] # Using Flask
    acct = stripe.Account.retrieve({CONNECTED_STRIPE_ACCOUNT_ID})
    acct.account_token = token
    acct.save()
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    \Stripe\Stripe::setApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    $token = $_POST['token'];
    $acct = \Stripe\Account::retrieve({CONNECTED_STRIPE_ACCOUNT_ID});
    $acct->account_token => $token;
    $acct->save();
    
    String token = request.getParameter("token");
    Account acct = Account.retrieve({CONNECTED_STRIPE_ACCOUNT_ID});
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("account_token", "token");
    acct.update(params);
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var token = request.body.token; // Using Express
    stripe.accounts.update(
      {CONNECTED_STRIPE_ACCOUNT_ID},
      {
        account_token: token,
      }
    );
    
    // Set your secret key: remember to change this to your live secret key in production
    // See your keys here: https://dashboard.stripe.com/account/apikeys
    stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    token := r.FormValue("stripeToken")
    params := &stripe.AccountParams{
      AccountToken: stripe.String(token),
    }
    acct, err := account.Update("{CONNECTED_STRIPE_ACCOUNT_ID}", params)
    

    When using account tokens for updates:

    • An existing value is replaced with a new value.
    • If no new value is provided, the existing value remains.
    • You cannot unset an existing value.
    • The tos_shown_and_accepted parameter is ignored and can be omitted.
    • You can use an account token for an update whether or not an account token was originally used when creating the account.
    • If the account was originally created using an account token, you can only update values using another account token.

    For example, if an account is created with a token containing only a name and date of birth, you’d create a subsequent token containing only the address information and then perform an update account call to add the address details to the account.

    Removing legal entity details

    If you need to clear any legal entity values or explicitly set a value as null, you can only do so by providing empty strings as values in an update account call. This is true whether an account token was originally used or not. When removing information, you can only remove optional legal entity data (e.g., the second line of an address). All other legal entity information can only be updated, never removed.

    It is sometimes necessary to explicitly set a legal entity value as empty, such as when legal_entity.additional_owners needs to be set to null to indicate that a connected account has no additional owners. In this case, you should also pass the null value using an update account call rather than using an account token.

    Next steps

    Now that you know how to create and use account tokens, you may want to read:

    Questions?

    We're always happy to help with code or other questions you might have! Search our documentation, contact support, or connect with our sales team. You can also chat live with other developers in #stripe on freenode.

    Was this page helpful? Yes No

    Send

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.