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.
disclosuresis optional perCreateEntityRequestModel, 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 laterPATCH /entities/{entityId}) and step 6'sPOST /accountsfails
withU040:"Missing/Incomplete documents: [Document: DISCLOSURES - Missing fields: [ termsOfUse rule14b customerAgreement signedBy ] ]". SendtermsOfUse,customerAgreement,privacyPolicy, and
rule14bup front — each needsagreed,signedBy, andsignedWhen.
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.
identificationskeys come back uppercase (EIN,FTIN,
GIIN,FTNLO,SSN) and address type keys come back uppercase (PRIMARYvs. request'sprimary).
Don't assume a round-trip through your own storage preserves the casing you sent.disclosuresechoes
back the same shape sent.kyb.status: KYB_APPROVEDimmediately withstatus: PENDINGconfirms this is a
no-KYB partner — same two-tier pattern as the trust-entity flow.
einmust be unique across the partner — reusing one from an earlier test fails; a single-digit
change (as123426789does here) is enough for repeat sandbox runs.
type / subType reference
type / subType referencetype | Valid subType |
|---|---|
CORPORATION | S_CORPORATION, C_CORPORATION |
LLC | LLC_SINGLE_MEMBER, LLC_C_CORPORATION, LLC_S_CORPORATION, LLC_PARTNERSHIP |
PARTNERSHIP | PARTNERSHIP_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.
userIDis documented as a User's id, not an entity's — a captured test on the trust-entity flow
confirmsPOST /documentsaccepts the entity'sidin 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 PENDING → APPROVED /
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: APPROVEDimmediately,TAX_INFOis
auto-added,birthDay/birthMonth/birthYearcollapse into a singlebirthdate,SSNcomes back
masked, and adisplayName/languageget auto-populated onBASIC_INFO. TheDIRECTOR_INFOdocument
echoes back theinstitutionalID,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, 0–1).
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
theinterestedPartiesblock on step 6'sPOST /accounts, referencing whichever individual'sidyou
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, andbeneficiaryDetailsare documented as optional but are
enforced as required in practice — a captured trust-entity test shows omitting any one fails with
E032naming that exact field (or, forbeneficiaryDetails, naming its missing sub-fields). For a
business entity,beneficiaryDetailsis the entity's own name/address, not an individual director's.
userIDhere is the entity'sidagain, 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"
}
]
}
]
}'
userIDhere is the entity'sid, not an individual's. Confirm this against current Accounts API
behavior before relying on it in production — it isn't spelled out inAccountsAPI.json's schema itself,
only in DriveWealth's business-onboarding guide.
interestedPartieswith at least oneAUTHORIZED_USERis required for a business Account. Also pass
that same authorized user'sidastraderIDwhen placing orders via the Orders API.reportingRoleis
one ofAUTH3RD,AUTHREP,NTHOLDER,TRDHOLDER.
accountFundingTypeis required for partners that support both wallet and bulk funding types — a
captured trust-entity test showsPOST /accountsfailing withE032
("AccountFundingType is required for partners that support both wallet and bulk funding types") without
it.AccountReq's ownrequiredlist doesn't list it, so include it defensively; valid values are
CASH/CASHLESS.The entity also needs
disclosuresset (step 1) before this call succeeds — without it, this fails
withU040(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"
}
]
}
]
}
idis the entity's id plus a suffix (<entityID>.<accountSeq>) —userIDon the Account still
echoes back the plain entity id.accountNo(DWEP002516) is the separate human-readable identifier
used elsewhere (e.g. asset transfers).nicknameauto-generates from the entity's name and
accountMgmtType.status: OPENconfirms the Account is ready to fund and trade, andinterestedParties
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 withaccountFundingTypeandinterestedPartiesboth included up front.
Check KYB status
There's no separate kyb-status endpoint like the Users API's kyc-status — GET /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.status | Meaning |
|---|---|
KYB_NOT_READY | Entity hasn't submitted all required data/documents yet |
KYB_READY | All required info submitted, queued for processing |
KYB_PROCESSING_DIRECTORS | KYC in progress for the linked directors |
KYB_PROCESSING_ENTITY | Director KYC cleared; entity-level verification in progress |
KYB_MANUAL_REVIEW | Escalated — can take up to a week per DriveWealth's guidance |
KYB_DOC_REQUIRED | A supporting document is missing |
KYB_INFO_REQUIRED | Submitted entity data needs correction |
KYB_APPROVED | Terminal — cleared |
KYB_DENIED | Terminal — 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.ssnon the entity itself is documented as "Social Security Number of the grantor
for trust entity" — for a business entity, useein/ftin/giininstead.- 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.
Updated 2 days ago