Using Tokens to Securely Transmit Account Data

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

    Before charges and payouts are enabled for connected accounts, “Know Your Customer” (KYC) requirements need to be fulfilled. This is completed by providing Stripe with identity verification information about your users, which we then verify. Account tokens and person tokens provide a secure and reliable way to perform this task. Using tokens ensures that personally identifiable information (PII) doesn’t touch your servers, so your integration can operate in a PCI-compliant way. These tokens also allow Stripe to more accurately detect potential fraud.

    Tokens can only be used for:

    • Legal entity details (information about the business or individual)
    • Person details
    • Indicating acceptance of the Stripe Connected Account Agreement

    Tokens cannot be used for any other account information, including:

    • Configuration settings on the account (e.g., payout schedules)
    • Non-sensitive info on the account (e.g., support url, support phone)
    • The country of the connected 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 token that can be used in create and update API calls.

    Creating and using tokens

    As with other uses of Stripe.js, 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.

    The example in the steps below shows how to use account tokens and person tokens. Both types are required when providing legal entity and person details for companies. If you only onboard individuals, you can just use account tokens and the individual hash on the Account object to provide the required information.

    Step 1: Create an HTML form

    The first step is to create an HTML form that collects the required information for the account and the person. This includes acceptance of the Stripe Connected Account Agreement.

    Collecting account and person details

    Create form elements to collect the required information, such as name, address, and anything else that’s required in the user’s country.

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

    Presenting the Stripe Connected Account Agreement

    Platforms must make clear to their 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 account and person tokens.
    3. Sends the IDs of the received tokens 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 or person, to specify the kind of token to create
    • A generic object of information

    The JavaScript object provided as the second argument needs to parallel the structure of the Account or Person object you are tokenizing. Account tokens need either a top-level company or individual property, and person tokens need a top-level person property. Follow the object’s structure through all the required attributes. For example, line1 within address in the code block below is provided as person.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 (only account tokens are used for this).

    Tokens must still be used—to create or update a person—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 accountResult = await stripe.createToken('account', {
        business_type: 'company',
        company: {
          name: document.querySelector('.inp-company-name').value,
          address: {
            line1: document.querySelector('.inp-company-street-address1').value,
            city: document.querySelector('.inp-company-city').value,
            state: document.querySelector('.inp-company-state').value,
            postal_code: document.querySelector('.inp-company-zip').value,
          },
        },
        tos_shown_and_accepted: true,
      });
    
      const personResult = await stripe.createToken('person', {
        person: {
          first_name: document.querySelector('.inp-person-first-name').value,
          last_name: document.querySelector('.inp-person-last-name').value,
          address: {
            line1: document.querySelector('.inp-person-street-address1').value,
            city: document.querySelector('.inp-person-city').value,
            state: document.querySelector('.inp-person-state').value,
            postal_code: document.querySelector('.inp-person-zip').value,
          },
        },
      });
    
      if (accountResult.token && personResult.token) {
        document.querySelector('#account-token').value = accountResult.token.id;
        document.querySelector('#person-token').value = personResult.token.id;
        myForm.submit();
      }
    }
    

    Upon successfully receiving the tokens from Stripe, the above JavaScript stores the token IDs in a hidden form input and then submits the form (to your server). The final steps are for your server-side code to use the tokens to create an account and a person.

    Step 3: Create an account

    Using the token’s ID, create the account (the country and business type are provided outside the token).

    curl https://api.stripe.com/v1/accounts \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d country=US \
      -d type=custom \
      -d account_token=ct_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([
        "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
    const 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.)

    Make sure to note the account ID that’s returned so that you can use it to create person objects for the account.

    Step 4: Create a person

    Create a person by providing the token ID as the value for the person_token parameter (you also need the account ID the person is for). You can use the requirements hash on the Account object to determine what information needs to be collected and from which persons.

    curl https://api.stripe.com/v1/persons \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d first_name=Jane \
      -d last_name=Diaz \
      -d person_token=pt_BcgCQ1lBFIx9RUe7YiEtiWfq
    
    # 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'
    
    person_token = params[:token]
    
    account = Stripe::Account.create_person(
      account_id,
      {
        person_token: person_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'
    
    person_token = request.form['token'] # Using Flask
    person = stripe.Account.create_person(
      account_id,
      person_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'];
    $person = \Stripe\Account::createPerson(
      $account_id,
      [
        'person_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("person_token", token);
    
    Account acct = Account.retrieve(accountId);
    account.getPersons().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
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    var token = request.body.token; // Using Express
    stripe.accounts.createPerson(
      account_id,
      { person_token: token },
      function(err, bank_account) {
        // 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.PersonParams{
      Account: stripe.String(account_id),
      PersonToken: stripe.String(token),
    }
    person, err := person.New(params)
    

    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 verification[document][front] value in the generic object provided to the createToken() call:

    const result = await stripe.createToken('account', {
      person: {
        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: {
                front: fileData.id,
                },
            },
        },
      tos_shown_and_accepted: true,
    });
    

    Updating legal entity and person details

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

    Note that you must create and provide a new 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=ct_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]
    Stripe::Account.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.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    token = request.form['token'] # Using Flask
    stripe.Account.modify(
      {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\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    $token = $_POST['token'];
    \Stripe\Account::update(
      {CONNECTED_STRIPE_ACCOUNT_ID},
      [
        'account_token' => $token,
      ]
    );
    
    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
    const 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 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 or person token for an update whether or not a token was originally used when creating the account or person.
    • If the account or person was originally created using an account token, you can only update values using another 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 and person details

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

    It is sometimes necessary to explicitly set an entity or person value as empty, such as when company[address][line2] needs to be set to null because the address doesn’t have an apartment, suite, or building number. 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 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.

    On this page