Onboarding a Business Entity

Overview

A Business Entity is a corporation, LLC, or partnership opening a DriveWealth trading account. This is
type: CORPORATION | LLC | PARTNERSHIP on the Entities API. See
Creating an entity if you're not sure this is the one you need — a trust
(including an SMSF) uses type: TRUST and a different guide,
Onboarding a Trust Entity.

Create the entity

curl -X POST https://bo-api.drivewealth.io/back-office/entities \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ibID": "80f9b672-120d-4b73-9cc9-42fb3262c4b9",
    "type": "CORPORATION",
    "subType": "C_CORPORATION",
    "attributes": {
      "name": "Acme",
      "incorporationCountry": "USA",
      "incorporationProvince": "NY",
      "incorporationDate": "2019-01-01"
    },
    "identifications": {
      "ein": "123426789"
    },
    "contact": {
      "addresses": {
        "primary": {
          "street1": "123 Main Street",
          "street2": "Suite 101",
          "city": "Wilmington",
          "province": "DE",
          "zipcode": "19801",
          "country": "USA"
        }
      },
      "phone": "+12345678911",
      "email": "[email protected]"
    },
    "disclosures": {
      "termsOfUse": {
        "agreed": true,
        "signedBy": "Jane Smith",
        "signedWhen": "2026-09-08T19:00:00Z"
      },
      "customerAgreement": {
        "agreed": true,
        "signedBy": "Jane Smith",
        "signedWhen": "2026-09-08T19:00:00Z"
      },
      "privacyPolicy": {
        "agreed": true,
        "signedBy": "Jane Smith",
        "signedWhen": "2026-09-08T19:00:00Z"
      },
      "rule14b": {
        "agreed": true,
        "signedBy": "Jane Smith",
        "signedWhen": "2026-09-08T19:00:00Z"
      }
    }
  }'

Required top-level: ibID, type, attributes (needs name + incorporationCountry),
identifications, contact (needs addresses, phone, email). subType is required for
CORPORATION/LLC/PARTNERSHIP — see the table below.

disclosures is optional per CreateEntityRequestModel, but DriveWealth's own onboarding
documentation lists it as required, and a captured trust-entity test confirms it's enforced in
practice
— skip it here (or a later PATCH /entities/{entityId}) and step 6's POST /accounts fails
with U040: "Missing/Incomplete documents: [Document: DISCLOSURES - Missing fields: [ termsOfUse rule14b customerAgreement signedBy ] ]". Send termsOfUse, customerAgreement, privacyPolicy, and
rule14b up front — each needs agreed, signedBy, and signedWhen.

Response — 201

{
  "id": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb",
  "ibID": "80f9b672-120d-4b73-9cc9-42fb3262c4b9",
  "wlpID": "DW",
  "type": "CORPORATION",
  "subType": "C_CORPORATION",
  "attributes": {
    "name": "Acme",
    "incorporationCountry": "USA",
    "incorporationProvince": "NY",
    "incorporationDate": "2019-01-01"
  },
  "identifications": {
    "EIN": "123426789"
  },
  "contact": {
    "addresses": {
      "PRIMARY": {
        "street1": "123 Main Street",
        "street2": "Suite 101",
        "city": "Wilmington",
        "province": "DE",
        "zipcode": "19801",
        "country": "USA"
      }
    },
    "phone": "+12345678911",
    "email": "[email protected]"
  },
  "disclosures": {
    "termsOfUse": {
      "agreed": true,
      "signedBy": "Jane Smith",
      "signedWhen": "2026-09-08T19:00:00Z"
    },
    "customerAgreement": {
      "agreed": true,
      "signedBy": "Jane Smith",
      "signedWhen": "2026-09-08T19:00:00Z"
    },
    "rule14b": {
      "agreed": true,
      "signedBy": "Jane Smith",
      "signedWhen": "2026-09-08T19:00:00Z"
    },
    "privacyPolicy": {
      "agreed": true,
      "signedBy": "Jane Smith",
      "signedWhen": "2026-09-08T19:00:00Z"
    }
  },
  "kyb": {
    "status": "KYB_APPROVED",
    "statusWhen": "2026-09-08T21:46:18.834636729Z",
    "statusBy": "SYSTEM",
    "reasons": [
      {
        "code": "D201",
        "description": "KYB has been auto-approved by the system for a no-KYB partner."
      }
    ]
  },
  "tax": {
    "status": "TAX_READY",
    "message": "Entity is ready for tax processing"
  },
  "status": "PENDING",
  "createdAt": "2026-09-08T21:46:18.835447195Z",
  "updatedAt": "2026-09-08T21:46:18.835447195Z",
  "createdBy": "7c0e3e79-59ae-475d-bf76-85ea82b363af",
  "updatedBy": "7c0e3e79-59ae-475d-bf76-85ea82b363af",
  "taxData": {
    "fatcaData": {
      "applicable": false,
      "applicableFrom": "2026-09-08T21:46:18.834690680Z",
      "setBy": "SYSTEM"
    },
    "data": {}
  }
}

Response casing flips from the request. identifications keys come back uppercase (EIN, FTIN,
GIIN, FTNLO, SSN) and address type keys come back uppercase (PRIMARY vs. request's primary).
Don't assume a round-trip through your own storage preserves the casing you sent. disclosures echoes
back the same shape sent. kyb.status: KYB_APPROVED immediately with status: PENDING confirms this is a
no-KYB partner — same two-tier pattern as the trust-entity flow.

ein must be unique across the partner — reusing one from an earlier test fails; a single-digit
change (as 123426789 does here) is enough for repeat sandbox runs.

type / subType reference

typeValid subType
CORPORATIONS_CORPORATION, C_CORPORATION
LLCLLC_SINGLE_MEMBER, LLC_C_CORPORATION, LLC_S_CORPORATION, LLC_PARTNERSHIP
PARTNERSHIPPARTNERSHIP_GENERAL, PARTNERSHIP_LIMITED

Optional fields on the same call (or a later PATCH): investorProfile (annualRevenue, netWorthTotal,
investmentObjective, riskTolerance, liquidityNeeds, investmentExperience, timeHorizon) — the
entity-level equivalent of a User's INVESTOR_PROFILE_INFO — plus financialAffiliations and
industryClassification (NAICS code or other).

2. Upload formation documents

DriveWealth requires proof of both entity formation (articles of incorporation, LLC agreement, partnership
agreement) and business registration — combine each into a single multi-page PDF rather than splitting
across files. This goes through the Physical Documents API using type: BUSINESS_DOCUMENT:

curl -X POST https://bo-api.drivewealth.io/back-office/documents \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "<the entity'"'"'s id from step 1>",
    "type": "BUSINESS_DOCUMENT",
    "document": "data:image/jpeg;base64,<base64-encoded file>"
  }'

Required: userID, type, document (base64-encoded, data-URI prefixed). side (FRONT/BACK) is
optional.

userID is documented as a User's id, not an entity's — a captured test on the trust-entity flow
confirms POST /documents accepts the entity's id in this field; expect the same here.

Response — 200

{
  "id": "92a22c5b-5b0d-467a-aa0b-207dcdfd75ec",
  "type": "BUSINESS_DOCUMENT",
  "status": {
    "name": "NOT_SUBMITTED",
    "description": "Document has not been submitted for approval."
  },
  "active": true
}

status.name starts at NOT_SUBMITTED right after upload and moves through PENDINGAPPROVED /
REJECTED once DriveWealth reviews it — this upload call alone doesn't submit it for review.

Link directors and beneficial owners

Each control person or beneficial owner is created as a normal User (userType: INDIVIDUAL_TRADER) with a
DIRECTOR_INFO document pointing back at the entity via institutionalID:

curl -X POST https://bo-api.drivewealth.io/back-office/users \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userType": "INDIVIDUAL_TRADER",
    "username": "jane.director",
    "password": "my#1Account",
    "documents": [
      {
        "type": "BASIC_INFO",
        "data": {
          "firstName": "Jane",
          "lastName": "Smith",
          "country": "USA",
          "phone": "12025550149",
          "emailAddress": "[email protected]"
        }
      },
      {
        "type": "IDENTIFICATION_INFO",
        "data": {
          "value": "402724321",
          "type": "SSN",
          "citizenship": "USA"
        }
      },
      {
        "type": "PERSONAL_INFO",
        "data": {
          "birthDay": 14,
          "birthMonth": 6,
          "birthYear": 1990,
          "politicallyExposedNames": "NULL"
        }
      },
      {
        "type": "ADDRESS_INFO",
        "data": {
          "street1": "15 Exchange Place",
          "city": "Jersey City",
          "province": "NJ",
          "postalCode": "07302",
          "country": "USA"
        }
      },
      {
        "type": "DIRECTOR_INFO",
        "data": {
          "directorList": [
            {
              "institutionalID": "<the entity's id from step 1>",
              "title": "Chief Innovation Officer",
              "controlContact": true,
              "percentage": 0.52,
              "roles": ["CONTROL_PERSON", "BENEFICIAL_OWNER"]
            }
          ]
        }
      }
    ]
  }'

Response — 200

{
  "id": "32b96320-0610-4c3d-84bb-dc0fc71fb9a7",
  "username": "jane.director",
  "userType": {
    "name": "INDIVIDUAL_TRADER",
    "description": "Individual Trader"
  },
  "status": {
    "name": "APPROVED",
    "description": "User approved."
  },
  "parentIB": {
    "id": "80f9b672-120d-4b73-9cc9-42fb3262c4b9",
    "name": "DriveWealth"
  },
  "documents": [
    {
      "type": "ADDRESS_INFO",
      "data": {
        "street1": "15 Exchange Place",
        "city": "Jersey City",
        "province": "NJ",
        "postalCode": "07302",
        "country": "USA"
      },
      "description": "Physical address information"
    },
    {
      "type": "BASIC_INFO",
      "data": {
        "firstName": "Jane",
        "lastName": "Smith",
        "displayName": "JSmith",
        "emailAddress": "[email protected]",
        "phone": "12025550149",
        "country": "USA",
        "language": "en_US"
      },
      "description": "Name, email, phone, etc."
    },
    {
      "type": "DIRECTOR_INFO",
      "data": {
        "directorList": [
          {
            "title": "Chief Innovation Officer",
            "controlContact": true,
            "percentage": 0.52,
            "institutionalID": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb",
            "roles": ["CONTROL_PERSON", "BENEFICIAL_OWNER"]
          }
        ]
      },
      "description": "Director specific information for a user"
    },
    {
      "type": "IDENTIFICATION_INFO",
      "data": {
        "value": "****4321",
        "type": "SSN",
        "citizenship": "USA",
        "description": "Social Security Number"
      },
      "description": "ID Number and citizenship"
    },
    {
      "type": "PERSONAL_INFO",
      "data": {
        "birthdate": "1990-06-14",
        "politicallyExposedNames": "NULL"
      },
      "description": "Birth date, gender, marital status, etc."
    },
    {
      "type": "TAX_INFO",
      "data": {
        "usTaxpayer": true,
        "taxTreatyWithUS": false
      },
      "description": "Tax Information"
    }
  ],
  "wlpID": "DW",
  "referralCode": "20420C",
  "createdWhen": "2026-09-08T21:49:49.096Z",
  "updatedWhen": "2026-09-08T21:49:49.096Z"
}

Same no-KYC-partner pattern as the other User guides: status: APPROVED immediately, TAX_INFO is
auto-added, birthDay/birthMonth/birthYear collapse into a single birthdate, SSN comes back
masked, and a displayName/language get auto-populated on BASIC_INFO. The DIRECTOR_INFO document
echoes back the institutionalID, percentage, and both roles you sent.

roles is an array — repeat this call (or PATCH an existing director's User) for every control person and
beneficial owner. A single individual can hold both CONTROL_PERSON and BENEFICIAL_OWNER at once, as
shown above. Only BENEFICIAL_OWNER uses percentage (ownership share, 01).

Create authorized traders

Anyone else who'll manage the account day-to-day — without a director/beneficial-owner role on the entity —
is also created as userType: INDIVIDUAL_TRADER, the same shape as step 3 but without a DIRECTOR_INFO
document referencing this entity's institutionalID. Not covered in detail here; see
Creating a user.

A business Account must have at least one authorized user — a control person, beneficial owner, or
someone created in this step all qualify.
This isn't enforced by a separate API call; it's satisfied by
the interestedParties block on step 6's POST /accounts, referencing whichever individual's id you
want authorized (a director from step 3 works fine — no separate authorized-trader User is required
unless someone beyond the directors needs access).

Link a bank account for Travel Rule

Opening a CASH-funded Account requires an active linked bank account with bankAccountPurpose: TRAVEL_RULE first — a captured test on the trust-entity flow confirms POST /accounts fails with A080
("Account's user is missing an active bank account of purpose TRAVEL_RULE") without one; expect the same
requirement here. This is a separate API (LinkedBankAccountsAPI.json, POST /bank-accounts):

curl -X POST https://bo-api.drivewealth.io/back-office/bank-accounts \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "<the entity'"'"'s id from step 1>",
    "bankAccountNumber": "7442393174",
    "bankRoutingNumber": "110000000",
    "bankAccountNickname": "Business Checking",
    "bankAccountType": "CHECKING",
    "bankAccountPurpose": "TRAVEL_RULE",
    "bankName": "Bank of America",
    "bankAddress": "222 Broadway, New York City, NY, 10038",
    "bankCountry": "USA",
    "beneficiaryDetails": {
      "accountHolderName": "Acme",
      "accountHolderAddress": "123 Main Street, Suite 101, Wilmington, DE, 19801",
      "accountHolderCountry": "USA"
    }
  }'

bankName, bankAddress, bankCountry, and beneficiaryDetails are documented as optional but are
enforced as required in practice
— a captured trust-entity test shows omitting any one fails with
E032 naming that exact field (or, for beneficiaryDetails, naming its missing sub-fields). For a
business entity, beneficiaryDetails is the entity's own name/address, not an individual director's.

userID here is the entity's id again, same pattern as step 2.

Response — 200

{
  "id": "bank_62d48778-accd-468f-a825-fd6d773d811c",
  "userDetails": {
    "userID": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb",
    "username": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb",
    "firstName": "Acme",
    "email": "[email protected]",
    "parentIB": {
      "id": "80f9b672-120d-4b73-9cc9-42fb3262c4b9",
      "name": "DriveWealth"
    },
    "wlpID": "DW"
  },
  "bankAccountDetails": {
    "bankAccountNickname": "Business Checking",
    "bankAccountNumber": "****3174",
    "bankRoutingNumber": "110000000",
    "bankAccountType": "CHECKING",
    "bankName": "Bank of America",
    "bankAddress": {
      "addressLine1": "222 Broadway, New York City, NY, 10038",
      "country": "USA"
    }
  },
  "default": false,
  "status": "ACTIVE",
  "bankAccountPurpose": "TRAVEL_RULE",
  "beneficiaryDetails": {
    "accountHolderName": "Acme",
    "accountHolderAddress": "123 Main Street, Suite 101, Wilmington, DE, 19801",
    "accountHolderCountry": "USA"
  },
  "created": "2026-09-08T21:54:25.976Z",
  "updated": "2026-09-08T21:54:25.976Z"
}

bankAccountNumber comes back masked (****3174), and status: ACTIVE confirms the account is ready to
satisfy the Travel Rule requirement in the next step — this call worked on the first try with all the
"optional" fields included up front.

Open the business Account

curl -X POST https://bo-api.drivewealth.io/back-office/accounts \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "<the entity'"'"'s id from step 1>",
    "accountType": "LIVE",
    "accountManagementType": "BUSINESS_SELF",
    "tradingType": "CASH",
    "accountFundingType": "CASH",
    "interestedParties": [
      {
        "type": "AUTHORIZED_USER",
        "data": [
          {
            "id": "<the control person'"'"'s id from step 3>",
            "reportingRole": "AUTHREP",
            "tradeDiscretion": true,
            "from": "2026-09-08T00:00:00Z"
          }
        ]
      }
    ]
  }'

userID here is the entity's id, not an individual's. Confirm this against current Accounts API
behavior before relying on it in production — it isn't spelled out in AccountsAPI.json's schema itself,
only in DriveWealth's business-onboarding guide.

interestedParties with at least one AUTHORIZED_USER is required for a business Account. Also pass
that same authorized user's id as traderID when placing orders via the Orders API. reportingRole is
one of AUTH3RD, AUTHREP, NTHOLDER, TRDHOLDER.

accountFundingType is required for partners that support both wallet and bulk funding types — a
captured trust-entity test shows POST /accounts failing with E032
("AccountFundingType is required for partners that support both wallet and bulk funding types") without
it. AccountReq's own required list doesn't list it, so include it defensively; valid values are
CASH/CASHLESS.

The entity also needs disclosures set (step 1) before this call succeeds — without it, this fails
with U040 (see step 1's callout for the exact error).

accountManagementType for a business entity is BUSINESS_SELF, BUSINESS_ADVISORY, or
BUSINESS_RIA_MANAGED — don't use the TRUST_* values, those are for trust entities.

Response — 200

{
  "id": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb.1788904479738",
  "accountNo": "DWEP002516",
  "accountType": {
    "name": "LIVE",
    "description": "Live Account"
  },
  "accountMgmtType": {
    "name": "BUSINESS_SELF",
    "description": "Self Directed Business Account"
  },
  "accountHolderType": {
    "name": "I",
    "description": "An account that does not meet FINRA Rule 4215(c) or a proprietary trading account"
  },
  "accountFundingType": "CASH",
  "status": {
    "name": "OPEN",
    "description": "Open"
  },
  "tradingType": {
    "name": "CASH",
    "description": "Cash account"
  },
  "leverage": 1.00,
  "nickname": "Acme's Self Directed Business Account",
  "parentIB": {
    "id": "80f9b672-120d-4b73-9cc9-42fb3262c4b9",
    "name": "DriveWealth"
  },
  "taxProfile": {
    "taxStatusCode": "W-9",
    "taxRecipientCode": "CORPORATION"
  },
  "currencyID": "USD",
  "commissionID": "b3e985dd-9679-63dc-5dd5-9bd7982efecd",
  "beneficiaries": false,
  "userID": "09ebfc41-8109-4b75-a3cd-ad7c6c65eacb",
  "restricted": false,
  "gfvRestricted": false,
  "goodFaithViolations": 0,
  "pdtRestricted": false,
  "patternDayTrader": false,
  "patternDayTrades": 0,
  "freeTradeBalance": 0,
  "gfvPdtExempt": false,
  "buyingPowerOverride": false,
  "bod": {},
  "sweepInd": true,
  "interestFree": false,
  "openedWhen": "2026-09-08T21:54:39Z",
  "ignoreMarketHoursForTest": false,
  "flaggedForACATS": false,
  "regType": "CUST",
  "interestedParties": [
    {
      "type": "AUTHORIZED_USER",
      "data": [
        {
          "id": "32b96320-0610-4c3d-84bb-dc0fc71fb9a7",
          "reportingRole": "AUTHREP",
          "tradeDiscretion": true,
          "from": "2026-09-08T00:00:00Z"
        }
      ]
    }
  ]
}

id is the entity's id plus a suffix (<entityID>.<accountSeq>) — userID on the Account still
echoes back the plain entity id. accountNo (DWEP002516) is the separate human-readable identifier
used elsewhere (e.g. asset transfers). nickname auto-generates from the entity's name and
accountMgmtType. status: OPEN confirms the Account is ready to fund and trade, and interestedParties
echoes back the authorized user exactly as sent — jane.director's id from step 3 in this case. This call
succeeded on the first try with accountFundingType and interestedParties both included up front.

Check KYB status

There's no separate kyb-status endpoint like the Users API's kyc-statusGET /entities/{entityId}
carries everything, including a rolled-up kycStatus per linked director:

curl -X GET https://bo-api.drivewealth.io/back-office/entities/<entity id> \
  -H "Authorization: Bearer $DW_BEARER_TOKEN" \
  -H "dw-client-app-key: $DW_APP_KEY"

Response — 200

Pending — validate this call in sandbox and paste the actual response here.

The response's directors[] array includes each linked individual's kycStatus directly — you don't need
a separate GET /users/USERID/kyc-status call per director just to see where they stand.

status (coarse: PENDING/APPROVED/REJECTED/REVOKED/CLOSED) and kyb.status (granular) are the
same two-tier pattern as User KYC — and the two don't move together. A captured no-KYB-partner response
came back kyb.status: KYB_APPROVED with kyb.reasons[0] explaining "KYB has been auto-approved by the system for a no-KYB partner", while the entity's own status stayed PENDING. Don't gate on status;
kyb.status (plus kyb.reasons[] when present, each a {code, description} pair) is the one that reflects
reality. Whether you see this immediate approval or the full KYB_NOT_READY → … progression below depends
on whether your partner is configured do-KYB or no-KYB/verify-KYB — same distinction as User KYC, confirm
with DriveWealth which model you're on.

kyb.statusMeaning
KYB_NOT_READYEntity hasn't submitted all required data/documents yet
KYB_READYAll required info submitted, queued for processing
KYB_PROCESSING_DIRECTORSKYC in progress for the linked directors
KYB_PROCESSING_ENTITYDirector KYC cleared; entity-level verification in progress
KYB_MANUAL_REVIEWEscalated — can take up to a week per DriveWealth's guidance
KYB_DOC_REQUIREDA supporting document is missing
KYB_INFO_REQUIREDSubmitted entity data needs correction
KYB_APPROVEDTerminal — cleared
KYB_DENIEDTerminal — rejected; any Account already opened moves to a frozen accountStatus

DriveWealth's own KYB documentation shows a notes array (e.g. ["Need more doc"]) alongside reasons[]
on the kyb object — EntityKybResponseModel doesn't define it, so treat it as present-but-undocumented
rather than something to build strict parsing around.

Subscribe to entity.created/entity.updated on your SQS queue rather than polling this endpoint —
entity.updated carries previous/current KYB state so you can see exactly what changed.

Requirements vary by entity origin

  • Foreign (non-US) entities complete a W-8 form via a DriveWealth-generated ComplyExchange URL,
    pre-filled with the entity's identification details, instead of the standard US flow.
  • identifications.ssn on the entity itself is documented as "Social Security Number of the grantor
    for trust entity" — for a business entity, use ein/ftin/giin instead.
  • Confirm country/entity-type-specific document and disclosure requirements with DriveWealth before
    extending this guide's US-corporation example to another jurisdiction or entity type.

What's next

Once the entity clears KYB and its Account is open, funding and trading follow the same Accounts/Deposits
flows as an individual Account.


Did this page help you?