Embedded Finance integration guide
Build an embedded financial services integration with Issuing and Treasury.
Build a US embedded financial services offering using Stripe Issuing and Treasury. Use Issuing to create cards, and Treasury to store balances and fund card spend.
By the end of this guide, you’ll know how to:
- Create verified connected accounts representing your business customers with relevant Issuing and Treasury capabilities
- Create financial accounts that you can use as a wallet for your business customers and add funds to using an external bank account
- Create virtual cards for your business customers and use these cards to spend funds from a wallet
Before you begin
- Sign up for a Stripe account.
- Activate Issuing and Treasury in test mode from the Dashboard. For more information, see API access to Issuing and Treasury.
- Configure your Connect platform branding settings for your business and add an icon.
Create connected accounts
Create a connected account
Create a connected account to represent a business customer of your platform. For example, if your product is a SaaS platform for restaurants, each restaurant would be represented as a connected account.
Connect account types
Issuing only supports connected accounts that don’t use a Stripe-hosted Dashboard, and where your platform is responsible for requirements collection and loss liability, also known as a Custom connected account. Learn how to create connected accounts that work with Issuing. If your existing accounts don’t match this configuration, you must recreate them.
The following request creates a US-based connected account with the correct configuration and requests the requisite capabilities:
The user’s account information appears in the response:
{ ... "id": "{{CONNECTED_ACCOUNT_ID}}", "controller": { "stripe_dashboard": { "type": "none" }, "fees": { "payer": "application" }, "losses": { "payments": "application" }, "is_controller": true, "type": "application", "requirement_collection": "application" }, ... }
Note the connected account’s id
. You’ll provide this value to authenticate as the connected account by passing it into requests in the Stripe-Account
header.
If a connected account already exists, you can add the requisite capabilities by specifying the connected account id
in the request:
Verify the connected account
Choose one of the following onboarding options:
At this point, Stripe has created and verified the connected account with active
relevant capabilities to use Issuing and Treasury.
To learn more, see:
Create financial accounts and add funds
After you enable Treasury on your platform, add FinancialAccount objects to your platform architecture to enable the efficient storing, sending, and receiving of funds. Stripe attaches a financial account to your platform account after enablement, and lets you provision an individual financial account for each eligible connected account on your platform.
In the Stripe API, FinancialAccount
objects serve as the source and destination of money movement API requests. You request Features
through the API to assign to FinancialAccounts
that provide additional functionality for the financial accounts on your platform.
A financial account operates a distinct balance of funds from the connected account payments balance of the account it’s linked to. For example, the owner of a connected account on your platform might have a 100 USD connected account balance and a 200 USD financial account balance. In this scenario, the connected account owner has a sum of 300 USD spread between their financial account and connected account balances. These two balances remain separate, but the API provides the ability to move money from the connected account balance to the financial account balance.
Multiple financial accounts
The multiple financial account beta feature enables you to open multiple financial accounts for a single connected account. Contact treasury-support@stripe.com to access test mode for this feature and join the wait list.
Create a Financial Account
After Stripe adds the treasury
capability to an account and it’s marked active
, you can create a FinancialAccount
object for the connected account. To do this, call FinancialAccounts
and request the Features
you want to provide:
The response, when you request features on financial account creation, indicates their status in the active_
, pending_
, and restricted_
parameters:
{ "object": "treasury.financial_account", "created": 1612927106, "id": "fa_123", "country": "US", "supported_currencies": ["usd"], "active_features": ["card_issuing"], "pending_features": ["financial_addresses.aba"], "restricted_features": [], // No FinancialAddress added as the financial_addresses.aba feature is not yet active "financial_addresses": [], "livemode": true, "status": "open", ... }
Activation might be instantaneous for some features (for example, card_
). However, other features, such as financial_
, activate asynchronously, might stay pending
for up to 30 minutes while Stripe communicates with external systems. After all the relevant features are active, you get confirmation on the treasury.
webhook listener. See Available features for more information on financial account features.
Link a bank account
To let your customers transfer money to and from an external account, create a SetupIntent
with the required parameters and attach it to self
to denote that the external account is owned by your customer:
The API response includes a unique identifier for the payment_
that’s used to reference this bank account when making ACH transfers:
{ "id": "{{SETUP_INTENT_ID}}", "object": "setup_intent", "next_action": { "type": "verify_with_microdeposits", "verify_with_microdeposits": { "arrival_date": 1642579200, "hosted_verification_url": "https://payments.stripe.com/microdeposit/sacs_test_xxx", "microdeposit_type": "amounts" } }, ... "payment_method": "{{PAYMENT_METHOD_ID}}", "payment_method_types": [ "us_bank_account" ] }
Before you can use a bank account, it must be verified using microdeposits (which we focus on here) or the faster financial connections option. The SetupIntent
response from the previous step includes a hosted_
which you must present to your customer for them to input the associated descriptor code of the microdeposit. Use the value SM11AA
to verify the bank account, or test a variety of other cases by using the test account numbers Stripe provides.
Microdeposit verification
Add funds to the financial account
At this point, the connected account has a FinancialAccount
that has been loaded with funds received from an InboundTransfer
that you can spend using cards or OutboundPayments
like ACH or wires.
To learn more, see:
- Getting permissions for InboundTransfers
- Working with Treasury financial accounts
- Using Treasury to move money
- Requesting features on a Financial Account
- Working with SetupIntents, PaymentMethods, and BankAccounts
- Moving money with Treasury using InboundTransfer objects
- Moving money with Treasury using ReceivedCredit objects
Use the card
Create an authorisation
To observe the impact of card activity on the associated balance, generate a test authorisation. You can do this in the Issuing page of the Dashboard for the connected account, or with the following call to the Authorisation API:
After approval, Stripe creates an Authorization
in a pending
state while it waits for capture. Note the authorisation id
that you’ll use to capture the funds:
{ "id": "iauth_1NvPyY2SSJdH5vn2xZQE8C7k", "object": "issuing.authorization", "amount": 1000, ... "status": "pending", "transactions": [], }
You can use retrieve the balance details of the financial account and see the impact of the authorisation:
The API response is a FinancialAccount
object with a balance
hash that details the funds and their availability:
{ "object": "treasury.financial_account", "id": "{{FINANCIAL_ACCOUNT_ID}}", ... "balance": { "cash": {"usd": 19000}, "inbound_pending": {"usd": 0}, "outbound_pending": {"usd": 1000} } }
The response indicates 190 USD is currently available for use with an additional 10 USD held in outbound_
from the pending
authorisation. You can now simulate capture of the authorisation with the API.
Capture the funds
Capture the funds using the following code:
After the authorisation is captured, Stripe creates an Issuing Transaction, the status
of the authorisation is set to closed
, and a ReceivedDebit
webhook is created with these details. Retrieving the balance details of the financial account again shows the outbound_
is now 0 USD while the available cash is remains 190 USD:
{ "object": "treasury.financial_account", "id": "{{FINANCIAL_ACCOUNT_ID}}", ... "balance": { "cash": {"usd": 19000}, "inbound_pending": {"usd": 0}, "outbound_pending": {"usd": 0} } }