Wallets and Self Directed Investing

Overview

Use this quick start guide to get up and running with DriveWealth’s REST API. This guide covers three “Hello, World!” examples that demonstrate how to make a stock purchase on behalf of a user:

  • Generate an Authentication Token
  • Create a Self-directed DriveWealth Brokerage Account
  • Make a Trade

Prerequisites

Before you begin, ensure you have your DriveWealth client app key (dw-client-app-key).

Idempotency-Key Header
Many of DriveWealth's APIs can take in an optional Idempotency-Key header. This is a unique ID that you create (e.g. using a GUID generation tool) to uniquely identify a request.

Should the request fail or be interrupted, you can retry the request with the same Idempotency-Key header value for up to four days.

Requests should never be unconditionally retried, as failing to receive a response does not necessarily mean that DriveWealth is not receiving and responding. We recommend an exponential backoff, or similar patten of retries, before switching to failover procedures such as:

Issue request at time T.

Retry 1: T + 1 second
Retry 2: T + 3 seconds
Retry 3: T + 10 seconds
Retry 4: T + 30 seconds

For more information see Idempotent Requests.



Generate an Authentication Token

An authentication token is required for your client app to make requests with our API on behalf of the end user. Once generated, this token must be included when invoking each subsequent DriveWealth REST endpoint in your app.


Auth Request

Follow the steps below to generate an authentication token:

  • (Optional) Generate or create a unique Idempotency-Key value.
  • Invoke POST /back-office/auth and pass in the following:
    • For the header:
      • Idempotency key as the Idempotency-Key (optional)
      • Client app ID as the dw-client-app-key
    • For the body:
      • clientID as the value retrieved when generating Sandbox keys
      • clientSecret as the value retrieved when generating Sandbox keys
curl --request POST \
     --url https://bo-api.drivewealth.io/back-office/auth/tokens \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'dw-client-app-key: 69204e73-561d-4...' \
     --data '{"clientID": "0oa5rc70..","clientSecret": "fr2k5wntp..."}'

Auth Response

The authToken field in the response contains the generated authentication token:

{
    "token_type": "Bearer",
    "expires_in": "3600",
    "access_token": "eyJraWQiOiJjY1lyLVRDUTZBR0w5OWl3TTFyMjAwWlNSdnI0dVBCZ3QxZU42eDhyRVVrIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULmkwRmJtbzJkdU5Ya3EzREtyU3NkVTN4M3V3MnljSjhTdkctel9hMFM0VWMiLCJpc3MiOiJodHRwczovL2FwMS1kcml2ZXdlYWx0aC5va3RhcHJldmlldy5jb20vb2F1dGgyL2F1czJ6bWJsNnBOcE4zelZEMWQ3IiwiYXVkIjoiRFdBdXRoU2VydmVyREVWIiwiaWF0IjoxNjY0OTA4OTA2LCJleHAiOjE2NjQ5MTI1MDYsImNpZCI6IjBvYTVubnk0bzlCZU1zQVlRMWQ3Iiwic2NwIjpbImFsbF90cmFkZXIiXSwic3ViIjoiMG9hNW5ueTRvOUJlTXNBWVExZDciLCJwcm9maWxlIjp7InBlcm1pc3Npb25JRCI6IjY5NTQ3OWFhLTVmN2ItNDRhOC1hMTE4LWFhOWU2N2M3YmUyZSIsInJvbGUiOiJBTExfVFJBREVSIiwicGFydG5lcklEIjoiMThkNTk3NjctNzNiOC00YTM0LWE1NDItMWNjZDIyYmEzNjAyIiwidXNlcklEIjoiNzA1YzFiMDMtM2Y2YS00MmFhLTgwN2EtMWY0NGMwNjc0ZDhmIn19.p3fspVtifQ_Gr4K3pi5fTorCBrcuVkRxk-yNLANgiKvl3t0BKraMT7_Y8c8opsKmNUwLS2K3YlBA0vrskzxeacWtEDx_JGtz_zKS_GXWTPDNNd77Zy0P6vfNfDjc_Hbzpp90dAICrTwvrcihNbyLeL3Zq7LisGpDkYtdxwB73AHtU6qIQvPY-iYaWBLfJ9IZrTTNWd5Qqy8ICJNunrS5riD2O3o4idyzMoUnFimUAoiAwgqtSOh4Loe57kPQsCgNRoba0zbnXKNd0eyMHCCdM0BXW_uhyJIfdGUXVzCcg9k_G80sWnefTeitwdX0S657vKHTjyLsGJSc06ZggGdlag",
    "scope": "all_trader"
}

You will use the generated authToken in the sections below to make requests on behalf of the user in your client app.



Create a Self-directed DriveWealth Brokerage Account

This section describes how to:

  • Create a User


Create a DriveWealth Brokerage Account

  • Create a User

The next step is to create a User entity in DriveWealth that represents the user you authenticated in the previous section.



User Request

Follow the steps below to prepare the request:

  • (Optional) Generate or create a unique Idempotency-Key value.
  • Invoke POST /back-office/users and pass in the following:
    • For the header:
      • Authentication token (generated in the previous section)
      • Idempotency key (optional)
      • Client app ID
      • The user's information in the body of the request.
curl --location --request POST 'https://bo-api.drivewealth.io/back-office/users' \
--header 'Authorization: Bearer :authToken' \
--header 'dw-client-app-key: f988...' \
--header 'Idempotency-Key: 2a5c0...' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "userType":"INDIVIDUAL_TRADER",
  "wlpID":"DWTT",
  "documents": [
       {
            "type": "BASIC_INFO",
            "data": {
                "firstName": "Daryl",
                "lastName": "Hall",
                "username": "DHall",
                "country": "USA", 
                "phone": "291...",
                "emailAddress": "[email protected]",
                "language": "en_US"
            }
        },
        {
            "type": "IDENTIFICATION_INFO",
            "data": {
                "value": "123456789",
                "type": "SSN",
                "citizenship": "USA"
            }
        },
        {
            "type": "PERSONAL_INFO",
            "data": {
                "birthDay": 3,
                "birthMonth": 12,
                "birthYear": 1990,
                "politicallyExposedNames": null
            }
        },
        {
            "type": "ADDRESS_INFO",
            "data": {
                "street1": "123 Main St",
                "city": "Chatham",
                "province": "NJ",
                "postalCode": "09812"
            }
        },
        {
            "type": "EMPLOYMENT_INFO",
            "data": {
                "status": "Employed",
                "broker": false,
                "type": "PROFESSIONAL",
                "position": "Police"
            }
        },
        {
            "type": "INVESTOR_PROFILE_INFO",
            "data": {
                "investmentObjectives": "Active_DAIly",
                "investmentExperience": "None",
                "annualIncome": 75000, 
                "networthLiquid": 58932,
                "networthTotal": 485003,
                "riskTolerance": "Low"
            }
        },
        {
            "type": "DISCLOSURES",
            "data": {
                "termsOfUse": true,
                "customerAgreement": true,
                "marketDataAgreement": true,
                "rule14b": true,
                "findersFee": false,
                "privacyPolicy": true,
                "dataSharing": true,
                "signedBy": "Chris Turkelton"
            }
        }        
  ],
  "parentIBID":"acb33c..."
}'


User Response

The id field in the response contains the ID for the newly-created user:

{
    "id": "6d454...",
    "userType": {
        "name": "INDIVIDUAL_TRADER",
        "description": "Individual Trader"
    },
    "status": {
        "name": "APPROVED",
        "description": "User approved."
    },
    "parentIB": {
        "id": "acb33c...",
        "name": "DriveWealth"
    },
    "documents": [
        {
            "type": "ADDRESS_INFO",
            "data": {
                "street1": "123 Main St",
                "city": "Chatham",
                "province": "NJ",
                "postalCode": "09812",
                "country": "USA"
            },
            "description": "Physical address information"
        },

        ...

    ],
    "wlpID": "DWTT",
    "referralCode": "CEB...",
    "createdWhen": "2022-04-20T21:49:34.452Z",
    "updatedWhen": "2022-04-20T21:49:34.452Z"
}

The ID generated for the user will be used in subsequent requests below to perform actions on behalf of the user.



Create a DriveWealth Brokerage Account

Now that the user has been registered with DriveWealth, the next step is to set up a DriveWealth brokerage account for that user.



Account Request

This example creates a simple self-directed account:

  • Invoke POST /back-office/accounts and pass in the following:
    • For the header:
      • Authentication token
      • Idempotency key (optional)
      • Client app ID
    • For the body:
      • id (generated in the previous section) via the userID field
      • Account setup information for the remaining body of the request
curl --location --request POST 'https://bo-api.drivewealth.io/back-office/accounts' \
--header 'Authorization: Bearer :authToken' \
--header 'dw-client-app-key: f988bb5f-2176-45d5-b417-57ce8e54e6b1' \
--header 'Idempotency-Key: e5c6f18a-d073-4e12-9954-c3a7b4d3e777' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "userID":"6d4547ab-9ae3-4b1f-9899-5f21536258d7",
  "accountType": "LIVE",
  "accountManagementType": "SELF",
  "tradingType": "CASH"
}'

Note: The account setup information required will vary depending on how the account is being configured. For more information, see Create Account.



Account Response

Theid field in the response contains the ID of the newly-created account:

{
    "id": "6d4547...",
    "accountNo": "ZBG...",
    "accountType": {
        "name": "LIVE",
        "description": "Live Account"
    },
    "accountMgmtType": {
        "name": "SELF",
        "description": "Self Directed Account"
    },
    "status": {
        "name": "OPEN",
        "description": "Open"
    },
    "tradingType": {
        "name": "CASH",
        "description": "Cash account"
    },
    "leverage": 1.00,
    "nickname": "Daryl's Self Directed Account",
    "parentIB": {
        "id": "acb33c...",
        "name": "DriveWealth"
    },
    "commissionID": "16497...",
    "beneficiaries": false,
    "userID": "6d45...",
    "restricted": false,
    "goodFaithViolations": 0,
    "patternDayTrades": 0,
    "freeTradeBalance": 0,
    "gfvPdtExempt": false,
    "buyingPowerOverride": true,
    "bod": {},
    "sweepInd": true,
    "interestFree": false,
    "openedWhen": "2022-04-20T22:01:30Z",
    "ignoreMarketHoursForTest": false,
    "flaggedForACATS": false
}

🚧

Note: Funding is specific to DIY accounts. It doesn't apply to wallet accounts since it is on a net-settlement basis.



For the purposes of quickly making a trade using the sandbox, this quickstart intentionally skips this step. In practice, you would normally:

Link an External Bank Account
In order to fund trades, the user's external bank account needs to be linked to their DriveWealth account.

  • Invoke POST /back-office/bank-accounts and pass the user's ID via the userID body field along with the external bank account information.
  • Check if the status field in the response indicates if the bank account was successfully linked (i.e. is set to ACTIVE).\

For Individually Funded Accounts

  • Fund the Account where you will use an endpoint to instantly fund the user's DriveWealth brokerage account.

Fund the Account

For this quickstart, use POST /back-office/funding/deposits to instantly fund the user's DriveWealth brokerage account.



Individual Funding Request

  • Invoke POST /back-office/accounts and pass in the following:
    • For the header:
      • Authentication token
      • Idempotency key (optional)
      • Client app ID
    • For the body:
      • accountNo of the user's DriveWealth brokerage account
      • Funding details including amount, currency, and type
curl --location --request POST 'https://bo-api.drivewealth.io/back-office/funding/deposits' \
--header 'Authorization: Bearer :authToken' \
--header 'dw-client-app-key: f988...' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "accountNo": "ZBG...",
  "amount": 500,
  "currency": "USD",  
  "type": "INSTANT_FUNDING", 
  "note": "Some money for funding" 
}'


Individual Funding Response

Theid field in the response identifies the funding request:

{
    "id": "ZBCB000...",
    "accountNo": "ZBC...",
    "category": "DEPOSIT",
    "currency": "USD",
    "amount": 500,
    "status": {
        "id": 1,
        "message": "Pending",
        "updated": "2022-04-26T17:56:25.295Z"
    },
    "source": {
        "id": "INSTANT_FUNDING",
        "brand": "Instant funding",
        "meta_info": "Some money for funding"
    },
    "created": "2022-04-26T17:56:25.295Z",
    "accountID": "261fb...",
    "userID": "261fb...",
    "transactionCode": "JOURNAL",
    "wlpFinTranTypeID": "f197...",
    "batch": true,
    "account_number": "ZBG..."
}


Make a Trade

Everything is now set up and your client app can now make a trade on behalf of the user. The following subsections show how to:

  • Purchase a Stock
  • Verify the Trade Order
  • The POST /back-office/orders endpoint is used to buy and sell stocks.


Trade Request

  • Invoke POST /back-office/accounts and pass in the following:
    • Values generated from Create a DriveWealth Brokerage Account:
      • The user's linked bank account number in the bankAccountNumber body field.
      • DriveWealth account number in the accountNo body field.
      • The remaining body fields to specify the order details.
curl --location --request POST 'https://bo-api.drivewealth.io/back-office/orders' \
--header 'Authorization: Bearer :authToken' \
--header 'dw-client-app-key: f988...' \
--header 'Idempotency-Key: 175bf...' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data-raw '{
  "bankAccountNumber":"12345",
  "accountNo":"yyy",
  "orderType":"MARKET",
  "symbol":"VTI",
  "side":"BUY",
  "quantity":"10"
}'


Trade Response

The orderID field uniquely identifies the order and can be used in subsequent requests (e.g. to Verify the Trade Order). The orderNo field is a user-friendly order identifier that you can display to the user:

{
  "orderID": "EF.418a55...",
  "orderNo": "EFXM000103"
}


Verify Trade Request

Invoke GET /back-office/orders/{order-id} to check the status of stock purchase.

Pass the orderID generated in the previous section in the {order-id} path parameter:

curl --location --request GET 'https://bo-api.drivewealth.io/back-office/orders/EF.418a55...' \
--header 'Authorization: Bearer :authToken' \
--header 'dw-client-app-key: f988...' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json'


Verify Trade Response

The status field in the response provides the current state of the order. In this example the value is FILLED, indicating that the stock has been successfully purchased:

{
  "id": "GB.703...",
  "orderNo": "EFXM000103",
  "type": "MARKET",
  "side": "BUY",
  "status": "FILLED",
  "symbol": "VTI",
  "averagePrice": 16.07,
  "totalOrderAmount": 10,
  "cumulativeQuantity": 0.92304,
  "quantity": 0.92304,
  "amountCash": 1500,
  "fees": 0.01,
  "createdBy": "cc07f9...",
  "userID": "3bfdb8...",
  "accountID": "cc07f91...",
  "accountNo": "DWRW000001",
  "created": "2019-02-14T18:56:07.411Z"