Creating Destination Charges on Your Platform

    With Connect, you can make charges through your platform account on behalf of connected accounts and take fees in the process.

    Connect supports three approaches for processing charges on behalf of a connected account. For Express and Custom accounts, the easiest route is to create the charge on the platform account and use the destination parameter to indicate the connected account. Using this approach, the platform is responsible for the cost of the Stripe fees, refunds, and chargebacks.

    This approach best fits an on-demand model, wherein customers interact with the platform and the platform leverages vendors (e.g., Lyft). This model also has a simple relationship between the charge (e.g., for the ride) and the transfer (e.g., to the individual driver).

    To charge on the platform while setting a destination, perform a standard create charge request while providing the connected account ID as the destination[account] value:

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1000 \
       -d currency=usd \
       -d source=tok_visa \
       -d destination[account]="{CONNECTED_STRIPE_ACCOUNT_ID}"
    
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      :amount => 1000,
      :currency => "usd",
      :source => "tok_visa",
      :destination => {
        :account => "{CONNECTED_STRIPE_ACCOUNT_ID}",
      }
    })
    
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1000,
      currency="usd",
      source="tok_visa",
      destination={
        "account": "{CONNECTED_STRIPE_ACCOUNT_ID}",
      }
    )
    
    // 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_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1000,
      "currency" => "usd",
      "source" => "tok_visa",
      "destination" => array(
        "account" => "{CONNECTED_STRIPE_ACCOUNT_ID}",
      ),
    ));
    
    // 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_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("amount", 1000);
    params.put("currency", "usd");
    params.put("source", "tok_visa");
    Map<String, Object> destinationParams = new HashMap<String, Object>();
    destinationParams.put("account", "{CONNECTED_STRIPE_ACCOUNT_ID}");
    params.put("destination", destinationParams);
    Charge charge = Charge.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_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1000,
      currency: "usd",
      source: "tok_visa",
      destination: {
        account: "{CONNECTED_STRIPE_ACCOUNT_ID}",
      },
    }).then(function(charge) {
      // 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    params := &stripe.ChargeParams{
      Amount: 1000,
      Currency: "usd",
      Destination: &stripe.DestinationParams{
        Account: "{CONNECTED_STRIPE_ACCOUNT_ID}",
      },
    }
    params.SetSource("tok_visa")
    
    charge, err := charge.New(params)
    

    The example uses a test tokentok_visa—but you could tokenize a test card using Stripe.js and Elements or Stripe Checkout instead.

    When using the destination[account] parameter, the token must be created using the platform’s publishable key. If charging a Customer object, the Customer must exist within the platform account.

    The charge is attributed to the destination account on applicable tax reporting (e.g., a 1099 tax form).

    Collecting platform fees

    With Connect, your platform can earn money while processing charges. When using the destination[account] parameter, you effectively take a fee by using the destination[amount] parameter.

    The destination[amount] is a positive integer reflecting the amount of the charge to be transferred to the destination[account]. Calculate this value by subtracting your platform’s fees from the charge amount:

    curl https://api.stripe.com/v1/charges \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d amount=1000 \
       -d currency=usd \
       -d source=tok_visa \
       -d destination[amount]=877 \
       -d destination[account]="{CONNECTED_STRIPE_ACCOUNT_ID}"
    
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = Stripe::Charge.create({
      :amount => 1000,
      :currency => "usd",
      :source => "tok_visa",
      :destination => {
        :amount => 877,
        :account => "{CONNECTED_STRIPE_ACCOUNT_ID}",
      }
    })
    
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    charge = stripe.Charge.create(
      amount=1000,
      currency="usd",
      source="tok_visa",
      destination={
        "amount": 877,
        "account": "{CONNECTED_STRIPE_ACCOUNT_ID}",
      }
    )
    
    // 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_BQokikJOvBiI2HlWgH4olfQ2");
    
    $charge = \Stripe\Charge::create(array(
      "amount" => 1000,
      "currency" => "usd",
      "source" => "tok_visa",
      "destination" => array(
        "amount" => 877,
        "account" => "{CONNECTED_STRIPE_ACCOUNT_ID}",
      ),
    ));
    
    // 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_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("amount", 1000);
    params.put("currency", "usd");
    params.put("source", "tok_visa");
    Map<String, Object> destinationParams = new HashMap<String, Object>();
    destinationParams.put("amount", 877);
    destinationParams.put("account", "{CONNECTED_STRIPE_ACCOUNT_ID}");
    params.put("destination", destinationParams);
    Charge charge = Charge.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_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.charges.create({
      amount: 1000,
      currency: "usd",
      source: "tok_visa",
      destination: {
        amount: 877,
        account: "{CONNECTED_STRIPE_ACCOUNT_ID}",
      },
    }).then(function(charge) {
      // 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    params := &stripe.ChargeParams{
      Amount: 1000,
      Currency: "usd",
      Destination: &stripe.DestinationParams{
        Amount: 877,
        Account: "{CONNECTED_STRIPE_ACCOUNT_ID}",
      },
    }
    params.SetSource("tok_visa")
    
    charge, err := charge.New(params)
    

    Keep in mind:

    • The destination[amount] is capped at the total transaction amount
    • The amount is always processed in the same currency as the transaction
    • Your platform separately pays the Stripe fees on the charge
    • No additional Stripe fees are applied to the amount

    Flow of funds with fees

    With the above code, the destination[amount] ($8.77) is added to the connected account’s pending balance. The charge total less the Stripe fees (on the charge amount) less the destination[amount] is added to the platform account’s pending balance ($0.64, which is $10.00 - $0.59 - $8.77).

    The destination[amount] becomes available on the connected account’s normal transfer schedule, just like funds from regular Stripe charges.

    Platforms can track how much they retain from destination[amount] charges by looking at the Destination Platform Fee column in the Balance history export.

    If you process payments in multiple currencies, you should also read how that is handled in Connect.

    Issuing refunds

    Charges created on the platform account can be refunded using the platform account's secret key. When refunding a charge that has a destination[account], by default the destination account keeps the funds that were transferred to it, leaving the platform account to cover the negative balance from the refund. To pull back the funds from the connected account to cover the refund, set the reverse_transfer parameter to true when creating the refund:

    curl https://api.stripe.com/v1/refunds \
       -u sk_test_BQokikJOvBiI2HlWgH4olfQ2: \
       -d charge="{CHARGE_ID}" \
       -d reverse_transfer=true
    
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    refund = Stripe::Refund.create({
      :charge => "{CHARGE_ID}",
      :reverse_transfer => true,
    })
    # 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    refund = stripe.Refund.create(
      charge="{CHARGE_ID}",
      reverse_transfer=True,
    )
    // 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_BQokikJOvBiI2HlWgH4olfQ2");
    
    $refund = \Stripe\Refund::create(array(
      "charge" => "{CHARGE_ID}",
      "reverse_transfer" => true,
    ));
    // 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_BQokikJOvBiI2HlWgH4olfQ2";
    
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("charge", "{CHARGE_ID}");
    params.put("reverse_transfer", true);
    Refund refund = Refund.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_BQokikJOvBiI2HlWgH4olfQ2");
    
    stripe.refunds.create({
      charge: "{CHARGE_ID}",
      reverse_transfer: true,
    }).then(function(refund) {
      // 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_BQokikJOvBiI2HlWgH4olfQ2"
    
    params := &stripe.RefundParams{
      Charge: "{CHARGE_ID}",
      Transfer: true,
    refund, err := refund.New(params)
    

    Further reading

    Discover what other Connect functionality is available.