# Adding funds to your platform balance with payment method ## Overview We provide platforms with several money movement APIs to manage users’ funds. To fund a merchant balance, platforms can create a top-up to pull funds from a user’s external bank account by providing a payment method. This guide describes how to create a payment method with an external bank account and add funds to the merchant balance with the payment method. ## SetupIntents and PaymentMethods A [PaymentMethod](https://docs.stripe.com/payments/payment-methods.md#payment-method-object) is a way to save account credentials for a US-based bank account for future use. After setup succeeds, you can use the same PaymentMethod multiple times to move funds into the merchant balance. [SetupIntents](https://docs.stripe.com/payments/setup-intents.md) are a state machine that allow you to set up a PaymentMethod to use with these money movement APIs. Use the [SetupIntents API](https://docs.stripe.com/api/setup_intents.md) to save the credentials as a PaymentMethod and optimize them for the API you intend to use it with. For example, when setting up a US bank account, it might be necessary to verify the bank account before debiting it. We update the `SetupIntent` object throughout the process. ### Create a SetupIntent to save US bank account details A [SetupIntent](https://docs.stripe.com/api/setup_intents.md) is an object that represents your intent to set up a payment method for usage with a money movement API endpoint. The `SetupIntent` tracks the steps of this set up process. See [Setting up a us_bank_account PaymentMethod](https://docs.stripe.com/payments/ach-direct-debit/set-up-payment.md) for information on how to set up a PaymentMethod for creating Payments and verifying the bank account. The process for setting up PaymentMethods is similar to the money movement APIs described in this guide. When setting up PaymentMethods for top-ups with SetupIntents, the following fields are the most relevant: - [flow_directions](https://docs.stripe.com/api/setup_intents/create.md#create_setup_intent-flow_directions): this array indicates the directions of money movement. Top-ups require `inbound` included in this array. - [attach_to_self](https://docs.stripe.com/api/setup_intents/create.md#create_setup_intent-attach_to_self): a boolean flag to indicate whether you want to attach this PaymentMethod to the in-context Stripe account. Set this to `true` to create an account-attached PaymentMethod for managing this Stripe account’s own money movement flows. - [mandate](https://docs.stripe.com/api/setup_intents/create.md#create_setup_intent-mandate_data): an object with a `customer_acceptance` field having the `type` `offline`. Depending on the `flow_directions` you specify, you might require [permission from the user](https://docs.stripe.com/payments/setup-intents.md#mandates) to save the PaymentMethod. Creating this agreement (or mandate) up front allows you to charge the PaymentMethod later. Add terms to your website or app that state how you plan to process payments and let users opt in. At a minimum, make sure that your terms cover the following: - The user’s permission for you to initiate a payment or a series of payments on their behalf - The anticipated frequency of payments (one-time or recurring) - How the payment amount is determined You need the user’s permission for debiting an external US bank account with top-ups. You don’t need permission for sending money to a bank account. To create a SetupIntent, you must either use an existing PaymentMethod with the `payment_method` parameter or provide new credentials using the inline `payment_method_data` parameter. ```curl curl https://api.stripe.com/v1/setup_intents \ -u "<>:" \ -d attach_to_self=true \ -d "flow_directions[]=inbound" \ -d "payment_method_types[]=us_bank_account" \ -d "payment_method_data[type]=us_bank_account" \ -d "payment_method_data[us_bank_account][routing_number]=12341234" \ -d "payment_method_data[us_bank_account][account_number]=0123456789" \ -d "payment_method_data[us_bank_account][account_holder_type]=individual" \ -d "payment_method_data[billing_details][name]=Jenny Rosen" \ --data-urlencode "payment_method_data[billing_details][email]=jenny.rosen@example.com" \ -d "payment_method_options[us_bank_account][verification_method]=microdeposits" \ -d "mandate_data[customer_acceptance][type]=offline" \ -d confirm=true ``` ### Set up your default bank account as a PaymentMethod To set up your default bank account as a valid `PaymentMethod`, pass it to the `SetupIntent` as follows: ```curl curl https://api.stripe.com/v1/setup_intents \ -u "<>:" \ -d attach_to_self=true \ -d "flow_directions[]=inbound" \ -d "payment_method_types[]=us_bank_account" \ -d payment_method={{DEFAULT_BANK_ACCOUNT_ID}} \ -d "mandate_data[customer_acceptance][type]=offline" \ -d confirm=true ``` You can get your default USD bank account ID by fetching the external bank accounts stored on your account and looking for the `bank_account` object whose `default_for_currency` property is true. ```curl curl -G https://api.stripe.com/v1/accounts/{{ACCOUNT_ID}}/external_accounts \ -u "<>:" \ -d object=bank_account ``` If successful, we return a SetupIntent object with one of the following possible statuses: | Status | Description | Next steps | | ----------------- | ----------------------------------------------------------------------- | ------------------------------------------ | | `succeeded` | The bank account is instantly verified or verification isn’t necessary. | No action is needed. | | `requires_action` | Further action is needed to complete the bank account verification. | See `next_action` for further setup steps. | After successfully confirming the SetupIntent, an email confirmation of the mandate and collected bank account details must be sent to your customer. We send these by default, but you can [send custom notifications](https://docs.stripe.com/payments/ach-direct-debit.md#mandate-and-microdeposit-emails) instead. ## Top-ups Top-ups represent pull-based transfers from an external account you own into your merchant balance. You can create a top-up to move funds into your merchant balance by debiting your external US bank account. ### Create a top-up When you add funds through the API, a [top-up object](https://docs.stripe.com/api/topups/object.md) is created. ```curl curl https://api.stripe.com/v1/topups \ -u "<>:" \ -d amount=2000 \ -d currency=usd \ -d payment_method=pm_123 \ -d "description=Top-up for week of May 31" \ -d "statement_descriptor=Weekly top-up" ``` When you transfer funds, a statement descriptor appears on your banking statement for the transaction. The default statement descriptor is “top-up.” You can customize the statement descriptor and internal description for the top-up. ### Testing top-ups To test your integration end-to-end, we recommend using the [SetupIntents API](https://docs.stripe.com/connect/top-ups-with-payment-method.md#setup-intents-payment-methods) in a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes) environment to create a PaymentMethod, then passing that PaymentMethod into a top-up creation request. Valid PaymentMethods result in `succeeded` top-ups, while invalid PaymentMethods (for example, PaymentMethods of unsupported types, or PaymentMethods that aren’t set up for inbound flows) display the same errors in live mode. We also provide a set of test bank account numbers that you can pass into the payment method setup. Use these test bank account numbers to test top-ups. You can only use them with test secret keys. | Routing | Account | Type | | ----------- | -------------- | ------------------------------------------------ | | `110000000` | `000123456789` | Top-up succeeds. | | `110000000` | `000111111113` | Top-up fails with a `account_closed` code. | | `110000000` | `000111111116` | Top-up fails with a `no_account` code. | | `110000000` | `000222222227` | Top-up fails with an `insufficient_funds` code. | | `110000000` | `000333333335` | Top-up fails with a `debit_not_authorized` code. | | `110000000` | `000555555559` | Top-up fails with a `dispute_auth_revoke` code. | | `110000000` | `000444444440` | Top-up fails with an `invalid_currency` code. |