Building an on-demand app

    This guide is an in-depth walkthrough for implementing an on-demand app using Connect.

    For some businesses, the platform’s brand is at the center of the commerce: they aren’t just providing a software platform, they’re providing an end-to-end experience. For example, consider an on-demand app: Rates are set by the platform. Although a third party is providing the specific service, the platform is managing the experience, guaranteeing the quality, and handling the customer service.

    Thanks to Connect, the complexity of this entire commercial flow can be reduced to a single API call, as you identify the intended recipient of funds when a charge is processed. Additionally, Connect makes it easy to create and manage accounts to work with and pay your service providers.

    The following steps walk through an on-demand app implementation, although the recipe is applicable to any business that has the primary relationship with its customers and pays its service providers directly. This implementation makes some additional assumptions about your business:

    • The platform is responsible for all fees, disputes, fraud, and customer service.
    • The service provider is an independent contractor, not an employee.
    • The contractor would not have a Stripe login, and Stripe would not contact them.

    (Note that “service provider,” “contractor,” and “connected account” interchangeably refer to an individual providing services on behalf of your platform.)

    Getting prepared

    First, understand that when you, the on-demand app’s creator, control the entire experience, you create Custom accounts on behalf of your service providers. One of the most important considerations with Custom accounts is that you are entirely responsible for providing the necessary information about your contractors, as Stripe will never interact with them. This means you must:

    If you’re properly prepared to do the above—as prerequisites for creating a new account on behalf of a service provider—you’ll have a smoother onboarding process, and will reduce the likelihood of delays in paying contractors once they start working. Toward that end, it would make sense for you to create a page where all the necessary information can be provided. This would simply be a form—perhaps part of a contractor portal—where the service provider enters their:

    • Name
    • Address
    • Date of birth
    • Last 4 digits of their Social Security number

    (This assumes the contractor is a U.S. individual, not being paid as a corporation. Service providers in other countries would have different requirements.)

    Again, the contractor would also need to formally agree to Stripe’s Services Agreement, and you would note the timestamp and the contractor’s IP address as a record of that. As the above information would only need to be taken once, you will separately request the contractor’s bank (explained below).

    Creating accounts

    With the necessary information in hand, create a new Custom account for the service provider:

    curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d managed=true \ -d country=US \ -d "legal_entity[type]"=individual \ -d "legal_entity[first_name]"=Jane \ -d "legal_entity[last_name]"=Doe \ -d "legal_entity[address][city]"="San Francisco" \ -d "/* Other address fields */" \ -d "legal_entity[dob][day]"=31 \ -d "legal_entity[dob][month]"=12 \ -d "legal_entity[dob][year]"=1969 \ -d "legal_entity[ssn_last_4]"=1234 \ -d "tos_acceptance[date]"=1582380396 \ -d "tos_acceptance[ip]"=""

    The result of a successful API call will be the account information (not all fields are shown):

    { "id": "acct_12QkqYGSOD4VcegJ", "keys": { "secret": "sk_live_AxSI9q6ieYWjGIeRbURf6EG0", "publishable": "pk_live_h9xguYGf2GcfytemKs5tHrtg" }, "managed": true, "charges_enabled": true, "transfers_enabled": false, ... "legal_entity": { ... "verification": { "status": "pending", ... } }, "verification": { "fields_needed": ['bank_account'], "due_by": null, "contacted": false } }

    You’ll need to store the account ID to later control and use the account. Note that the response shows charges_enabled as true, meaning you can start processing payments on behalf of this contractor right now. The legal_entity[verification] hash’s status property is “pending”, meaning that Stripe is in the process of verifying the new account. The top-level verification property shows that a bank account is still required.

    In short, this contractor is ready to start working for your on-demand app, but can’t yet be paid (because of the lack of a bank account; to be remedied shortly).

    Processing payments

    To pay contractors directly, simply process the charge on your account, setting a destination parameter that identifies the Stripe account that should receive the funds from the payment (i.e., the contractor). This requires a payment token created using the platform’s publishable API key.

    curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1000 \ -d currency=usd \ -d source="{TOKEN}" \ -d destination=acct_12QkqYGSOD4VcegJ \ -d application_fee=200

    The customer is being charged $10.00, and you’re taking a $2.00 application fee. The payment appears as a charge in your account, along with a transfer from your account to the contractor’s account. The Stripe fees (of 59 cents) will come out of your account; you’ll net $1.41. The contractor receives $8.00.

    (Instead of using the token directly, you could choose to create customers in your, the platform’s, account. You would then create charges using the customer ID instead of a token source.)

    To be clear, these funds are directly going into your, and the contractor’s, Stripe accounts. The funds will become available for transfer to a bank account on the normal rolling basis. If you haven’t already done so, you’ll need to add a bank account in order for the contractor to actually receive the payment.

    Adding a bank account

    The final step in completing the flow of funds here is to update the service provider’s account by adding a bank account to which Stripe will transfer payments. Perhaps, on another form on your site, you’ll have your contractors manage their bank account, allowing new service providers to add one and existing contractors to change theirs.

    You can securely take a person’s banking information using Stripe.js, receiving a representative token in return. This can be added to the contractor’s Stripe account:

    curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d bank_account="{TOKEN}"

    The result of that successful API call will show payouts now enabled on the account:

    { ... "transfers_enabled": true, ... }

    While you’re at it, you can also dictate the contractor’s transfer schedule. For example, maybe you’ve said contractors are paid out every Thursday:

    curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d "transfer_schedule[interval]"=weekly \ -d "transfer_schedule[weekly_anchor]"=thursday

    With a bank account attached, and payments being processed, the contractor will now automatically be paid out by Stripe every Thursday for all funds that became available since the previous transfer. No additional effort is required on your part to make that happen!

    Using webhooks

    After registering your platform with Stripe, you’d want to be certain that you have a webhook defined. With Custom accounts, you’ll specifically need to watch for account.updated events, which Stripe uses to indicate a need for more information, among other things. Failure to respond to those events can result in delayed payouts to your contractors. For example, you might see this:

    { "id": "evt_1234", "account": "acct_12QkqYGSOD4VcegJ", ... "data": { "object": { ... "legal_entity": { "verification": { "status": "unverified" ... } }, "verification": { "fields_needed": ['legal_entity.personal_id_number'] "due_by": null, "contacted": false } }, "previous_attributes": { "legal_entity": { "verification": { "status": "pending" } }, "verification": { "fields_needed": [] } } } }

    This event is Stripe’s way of telling you:

    • This contractor’s verification failed (the status changed from pending to unverified).
    • Stripe now needs the contractor’s entire Social Security number (legal_entity.personal_id_number is in the fields_needed).
    • It’s not urgent, because due_by is null.

    If the due_by was set, the additional information would be required by that time (usually at least 3 days). Failure to provide that information by that time could result in payouts to the contractor being held.

    For any information required by Stripe, you’d request it from the contractor—if you did not have it already—and update the account.

    Running a promotion

    Everything is now going smoothly with paying your contractors and managing their accounts, but to drum up more business, you’ve decided to give each new customer the first service at no cost. However, your contractors aren’t working for free! Connect will help you out here, too.

    To handle this promotion, as the customer isn’t charged anything, you’ll instead represent each free service as a transfer from your Stripe account to the contractor’s:

    curl \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=800 \ -d currency=usd \ -d destination=acct_12QkqYGSOD4VcegJ

    This is similar to how a charge is processed, except no application fee is set, no token is required, and no Stripe fees will be assessed. The $8.00 will appear as a payment in the contractor’s account and will be automatically paid out next Thursday—just the same as with a conventional charge.

    Other recipes

    Looking to build another type of platform? Check out these other recipes.

    Was this page helpful?

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

    On this page