Crypto-as-a-Service
Complete Know Your Business (KYB) Verification
Overview
BitGo must verify the legitimacy of businesses you onboard to your platform to ensure regulatory compliance. The Know Your Business (KYB) API enables you to submit all required documentation to prove corporate existence, physical operational footprint, legal signing delegation, and identity verification for key stakeholders. You must complete KYB verification for each entity before they can use BitGo products on your platform.
Required Documents
Required documents for KYB verification are determined by four factors:
- Universal Requirements - Core identification documents that you must submit for every business and business owner on your platform.
- Legal Entity Structure - Documents that are specific to the legal structure of the business.
- Jurisdiction & Tax - Documents that are specific to jurisdiction and include tax documents.
- Business Types & BitGo Products - Documents that are specific to the business type and the BitGo products they'll use on your platform.
When you create a business or associated individual identity, BitGo returns the exact documents required to complete the KYB verification. However, you can expand the following to learn more now:
Universal
Entity Requirements
| Requirement | Document Type (documentType) |
Description |
|---|---|---|
| Authorized Signer | authorizedSigner |
Authorized signatory name, email, phone. |
| Billing Address | billingAddress |
Billing address. |
| Billing Contact | billingContact |
Billing contact name, email, phone. |
| Business Name | businessName |
Legal registered name. |
| Company Website Address | companyWebsiteAddress |
Official website URL. |
| Customer Base Locations | customerBaseLocations |
Countries/regions of customer base. |
| DBA Name | dbaName |
Doing-Business-As name. |
| Description of Business Activities | descriptionBusinessActivities |
What the business does. |
| EIN/TIN Identification Number | einTinIdentificationNumber |
EIN or Tax ID Number. |
| Formation Date | formationDate |
Date formed (YYYY-MM-DD). |
| Has Auditor | hasAuditor |
Has external auditor? |
| Has Legal Counsel | hasLegalCounsel |
Has legal counsel? |
| Incorporation Country Code | incorporationCountryCode |
Country of incorporation (e.g. USA). |
| Legal Entity Structure | legalEntityStructure |
Entity type (e.g. corporationCAndS, LLC, trusts). |
| Mailing Address | mailingAddress |
Mailing address (if different). |
| Other Entity ID | otherEntityId |
Secondary entity ID (state registration, etc.). |
| Physical Business Address | physicalBusinessAddress |
Principal business address. |
| Primary Business Type | primaryBusinessType |
Category of business activity. |
| Primary Operations Country Code | primaryOperationsCountryCode |
Country of primary operations. |
| Proof of Authorized Signatories |
|
Completed BitGo Authorized Signer Form or official corporate document confirming the designated individual has legal authority to execute contracts on behalf of the entity. |
| Proof of Principal Place of Business | proofOfPrincipalPlaceOfBusiness |
Recent utility bill, lease agreement, or bank statement (issued within the last 3 months) confirming the business's physical operating address. PO Boxes are not accepted. |
| Retail/Institutional Diligence | diligenceRetailInstitutional |
Retail vs institutional proportion (enum). |
| Sanction Affiliates | sanctionAffiliates |
Sanction-related affiliates? |
| Wallet Address | walletAddress |
Business blockchain wallet address. |
Individual Requirements
For each business, you must identify one control person (controlPerson). If there are other individuals who hold a 10% or more share of the business, then you must add them as a beneficial owner (beneficialOwner).
| Requirement | Document Type (documentType) |
Description |
|---|---|---|
| Address | address |
Residential address. |
| Birthdate | birthdate |
Date of birth (month, day, year). |
| Country of Citizenship | countryOfCitizenship |
Country of citizenship. |
| Country of Residence | countryOfResidence |
Country of residence — submit first. |
email |
Email address of the individual. | |
| First Name | nameFirst |
First name. |
| Government-Issued Photo ID | governmentId |
Valid, unexpired government-issued photo ID (passport, driver's license, or national identity card) for every individual listed under associatedPeople (beneficial owners, control persons, and platform admins). |
| Identification Number | identificationNumber |
Government ID or SSN. |
| Last Name | nameLast |
Last name. |
| Occupation | occupation |
Current occupation. |
| PEP Status | politicallyExposedPerson |
PEP status (true/false). |
| Phone Number | phoneNumber |
Phone with country code. |
| Residential Proof of Address | proofOfAddress |
Utility bill, residential bank statement, or government correspondence dated within the last 3 months verifying the primary residential address for each associated person. |
Legal Entity Structure
Defined with the legalEntityStructure field on the Create KYB Identity endpoint.
| Legal Structure | Schema Enum (legalEntityStructure) |
Document Type (documentType) |
Description |
|---|---|---|---|
| Corporation (C Corporation and S Corporation) | corporationCAndS |
|
|
| General Partnerships | generalPartnership |
|
|
| Government / State Owned | governmentOwned |
|
|
| Limited Liability Company (LLC) | llc |
|
|
| Partnership (Limited Partnerships and Limited Liability Partnerships) | partnershipLimitedAndLLP |
|
|
| Private Investment Company / Private Foundation | privateInvestmentOrFoundation |
|
|
| Publicly Traded Company (or 100% owned subsidiary) | publiclyTraded |
|
|
| Sole Proprietorship | soleProprietorship |
|
|
| Special Purpose Vehicle (SPV) / Segregated Portfolio Company (SPC) |
|
|
|
| Supranational Bodies | supranationalBodies |
foundingTreatyOrEquivalent |
Founding Treaty: Intergovernmental convention, founding treaty, or bilateral charter establishing the body. |
| Trusts | trusts |
certificateOfTrust |
Certificate of Trust: Formal legal instrument or trust deed verifying trust existence, identifying trustees, and defining trustee powers. |
| Unincorporated Business (including pooled investment vehicles) | unincorporatedBusiness |
|
|
Jurisdiction & Tax
Defined with the incorporationCountryCode and primaryOperationsCountryCode fields on the Update KYB Identity endpoint.
Note
Every business must submit either an IRS Form W-8 (w8) or Form W-9 (w9).
| Jurisdiction / Contracting Entity | Trigger Conditions | Document Type (documentType) |
Description |
|---|---|---|---|
| Japan |
|
proofOfJfsaLicense |
JFSA Proof of License: Official registration certificate issued by the Japanese Financial Services Agency. |
| Non-US / International | incorporationCountryCode != "USA" |
w8 |
Form W-8: Completed and signed IRS Form W-8BEN-E certifying foreign status for US tax withholding. |
| Non-US / International | Non-US registered entities | commercialRegister |
Commercial Register Extract: Official excerpt from national trade/company registry issued within the last 12 months. |
| Non-US / Offshore | Jurisdictions without public shareholder registries | certificateOfIncumbency |
Certificate of Incumbency: Document issued by registered agent/corporate secretary listing current directors and officers. |
| Singapore | Contracting with BitGo Singapore |
resolutionToOpenBitgoSingaporeAccount |
Singapore Corporate Resolution: Board resolution formally authorizing onboarding and account opening with BitGo Singapore. |
| United Arab Emirates (UAE) |
|
|
|
| United States | US entity incorporated > 12 months prior | certificateOfGoodStanding |
Certificate of Good Standing: State secretary extract dated within the last 12 months confirming active legal status. |
| United States |
|
w9 |
Form W-9: Completed and signed IRS Form W-9 confirming US legal entity name and EIN/TIN. |
Business Types & BitGo Products
Defined with the primaryBusinessType and requestedProducts fields on the Create KYB Identity and Update KYB Identity endpoints.
| Business Activity / Product | Trigger Field & Value | Document Type (documentType) |
Description |
|---|---|---|---|
| Casinos & Gambling | primaryBusinessType: "Casinos and Gambling Establishments" |
proofOfGamingLicense |
Gaming License: Official gambling or gaming license issued by the jurisdictional regulatory authority. |
| Custom Case Reviews | Ad-hoc compliance referral triggered during manual review | caseRequiredDocuments |
Case Required Documents: Dynamically created file slots assigned per-instance for specific transaction or compliance requests. |
| Enhanced Due Diligence (EDD) |
|
sourceOfWealth |
Source of Wealth: Audited financial statements, tax records, or banking documentation evidencing economic origin of capital. |
| Foreign Banking |
|
correspondentAccountCertification |
Correspondent Account Certification: Completed and signed FinCEN certification regarding correspondent accounts for foreign banks. |
| Regulated MSB / High-Risk FinTech |
|
financialCrimeComplianceQuestionnaire |
Compliance Questionnaire: BitGo AML/CFT compliance questionnaire detailing AML controls, transaction monitoring, and policies. |
| Trade / Go Account Products |
|
|
|
Prerequisites
- Get Started
- Set Up Organization
- You must be the service user.
- (Optional) Set up webhooks to follow the KYB process. Use the
identityStatusorganization webhook and listen for theproductRequestApprovedandproductRequestRejectedevents. To learn more, see Create Organization Webhook.
Cookbook
Need just the steps? Expand the cookbook below to get started:
Complete KYB VerificationOpen Cookbook1. Create Enterprise and Primary User
Endpoint: Create an Enterprise for an Organization
export ORGANIZATION_ID="<YOUR_ORGANIZATION_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export EMAIL="<YOUR_USER'S_EMAIL>"
export IDEMPOTENCY_KEY="<UUID_V4>"
curl -X POST \
"https://app.bitgo-test.com/api/v2/organization/$ORGANIZATION_ID/enterprise" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"email": "$EMAIL",
"idempotencyKey": "$IDEMPOTENCY_KEY",
"additionalAdmins": [],
"accountType": "entity" # This creates a business enterprise instead of an individual enterprise.
}'
Note
Generate a fresh UUID for each new request. Reuse the same key when you retry the same request, so BitGo recognizes the duplicate.
Step Result
The request does the following:
- Creates a new child enterprise within your parent organization.
- Creates a user for the child enterprise, who serves as the primary contact for the business.
- Assigns the service user to the child enterprise.
- Assigns organization admins to the child enterprise.
{
"enterpriseId": "68cc1b65564dc0f83892a49d1ee75626",
"userId": "68cc1b63564dc0f83892a32072a8b5c7"
}
2. Create Users for Associated Persons
Repeat this step for every beneficial owner, control person, and platform admin of the business.
Endpoint: Add a User to an Enterprise Within an Organization
export ORGANIZATION_ID="<YOUR_ORGANIZATION_ID>"
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export EMAIL="<YOUR_USER'S_EMAIL>"
curl -X POST \
"https://app.bitgo-test.com/api/v2/organization/$ORGANIZATION_ID/enterprise/{enterpriseId}/user" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"email": "$EMAIL"
}'
Step Result
You receive a user ID for each person. Save these IDs for use in Step 4.
{
"userId": "68cc1bc8b1b5017f12c5c1e3c04cd1d4"
}
3. Set Up Business Identity
Complete these sub-steps to create and populate the business identity.
3.1 Create Business Identity
Create the business identity and request the BitGo products they intend to use.
Choose Products
The products you request drive the KYB requirements. You can add additional later as your platform grows. Most platforms start with Trade and Go Account.
Endpoint: Create KYB Identity
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ORGANIZATION_ID="<YOUR_ORGANIZATION_ID>"
curl -X POST \
"https://app.bitgo-test.com/api/identity-service/v1/identities" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"type": "business",
"enterpriseId": "$ENTERPRISE_ID",
"organizationId": "$ORGANIZATION_ID",
"requestedProducts": [
{
"name": "Trade",
"bitgoOrg": "BitGo Trust"
},
{
"name": "Go Account",
"bitgoOrg": "BitGo Trust"
}
]
}
}'
Step Result
Save the identity id. This is the business identity ID.
{
"type": "business",
"organizationId": "659706890515c624f4f0871b879b00a6",
"enterpriseId": "68cc1b65564dc0f83892a49d1ee75626",
"business": {},
"associatedPeople": [],
"id": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"requestedProducts": [
{
"id": "1a595191-b22d-48f9-b816-4ca311a3f5a4",
"name": "Trade",
"bitgoOrg": "BitGo Trust",
"status": "missingLocation"
},
{
"id": "81948454-f74e-438e-b51e-75e3fdbac1d3",
"name": "Go Account",
"bitgoOrg": "BitGo Trust",
"status": "missingLocation"
}
],
"requirements": [],
"documents": [],
"finalizeSubmission": false
}
3.2 Add Business Location and Legal Entity Structure
Endpoint: Update KYB Identity
export BUSINESS_IDENTITY_ID="<BUSINESS_IDENTITY_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X PATCH \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$BUSINESS_IDENTITY_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"business": {
"physicalBusinessAddress": {
"street1": "123 4th St",
"city": "San Francisco",
"subdivision": "CA",
"zip": "94103",
"country": "USA"
},
"legalEntityStructure": "corporationCAndS",
"primaryBusinessType": "Crypto Services (Exchange, ATM, Borrow/Lend)",
"incorporationCountryCode": "USA",
"primaryOperationsCountryCode": "USA"
}
}'
Step Result
The requirements array returns all the KYB information that you must submit in Step 5. Requirements vary based on legal entity structure, location, and selected BitGo products. The following example is for a Corporation (C Corporation and S Corporation):
{
"type": "business",
"id": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"business": {
"physicalBusinessAddress": {
"street1": "123 4th St",
"city": "San Francisco",
"subdivision": "CA",
"zip": "94103",
"country": "USA"
},
"legalEntityStructure": "corporationCAndS",
"primaryBusinessType": "Crypto Services (Exchange, ATM, Borrow/Lend)",
"incorporationCountryCode": "USA",
"primaryOperationsCountryCode": "USA"
},
"requestedProducts": [
{
"name": "Trade",
"bitgoOrg": "BitGo Trust",
"status": "missingRequirements"
},
{
"name": "Go Account",
"bitgoOrg": "BitGo Trust",
"status": "missingRequirements"
}
],
"requirements": [
{
"kind": "document",
"name": "certificateOfIncorporation",
"status": "missing"
},
{
"kind": "document",
"name": "evidenceOfLegalStatus",
"status": "missing"
},
{
"kind": "document",
"name": "bylaws",
"status": "missing"
},
{
"kind": "document",
"name": "proofOfAuthorizedSignatories",
"status": "missing"
},
{
"kind": "document",
"name": "w9",
"status": "missing"
},
{
"kind": "businessInformation",
"name": "businessName",
"status": "missing"
},
{
"kind": "businessInformation",
"name": "einTinIdentificationNumber",
"status": "missing"
},
{
"kind": "businessInformation",
"name": "fundsSource",
"status": "missing"
},
{
"kind": "businessInformation",
"name": "amlAttestation",
"status": "missing"
},
{
"kind": "businessInformation",
"name": "legalEntityStructure",
"status": "submitted"
}
],
"finalizeSubmission": false
}
Track Product Status
The requestedProducts array returns a status that provides more information about the required KYB documents.
Statuses
| Status | Description | Action |
|---|---|---|
missingLocation |
BitGo needs the business location. | Redo Step 3.2. |
missingEntityStructure |
BitGo needs the four structural fields. | Redo Step 3.2. |
missingRequirements |
Fields or documents are still missing. | Submit the items in requirements. |
readyForSubmission |
You submitted everything. | Finalize business identity Step 8. |
inReview |
BitGo is reviewing the identity. | Wait for the decision from BitGo. |
approved or rejected |
BitGo made a final decision. | Listen for the webhook event. |
4. Set Up Associated Persons
Complete these sub-steps to create and populate an individual identity for each beneficial owner and control person.
| Role | Rule |
|---|---|
controlPerson |
Exactly one. No more, no less. |
beneficialOwner |
Required for each person who holds 10% or more of the business. |
4.1 Create Individual Identities for Associated Persons
Using the userId from Step 2, create an individual identity for each control person and beneficial owner. You don't need to request products for associated persons.
Endpoint: Create KYB Identity
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export ASSOCIATED_PERSON_USER_ID="<USER_ID_FOR_THIS_ASSOCIATED_PERSON>"
curl -X POST \
"https://app.bitgo-test.com/api/identity-service/v1/identities" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"type": "individual",
"userId": "'"$ASSOCIATED_PERSON_USER_ID"'",
"requestedProducts": []
}'
Step Result
Save the identity id for each person.
{
"type": "individual",
"userId": "68cc1bc8b1b5017f12c5c1e3c04cd1d4",
"individual": {},
"id": "df114ee7-7dc9-431e-aeae-fe4294f789cc",
"requestedProducts": [],
"requirements": [],
"documents": [],
"finalizeSubmission": false
}
4.2 Add Associated Persons to Business Identity
BitGo generates the KYB requirements for each person once you link them to the business identity.
If no one holds 10% or more of the business, the beneficial owner requirement defaults to submitted. You can still add beneficial owners.
Endpoint: Update KYB Identity
export BUSINESS_IDENTITY_ID="<BUSINESS_IDENTITY_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export BENEFICIAL_OWNER_USER_ID="<BENEFICIAL_OWNER_USER_ID>"
export CONTROL_PERSON_USER_ID="<CONTROL_PERSON_USER_ID>"
curl -X PATCH \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$BUSINESS_IDENTITY_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"associatedPeople": [
{
"role": "beneficialOwner",
"identityId": "'"$BENEFICIAL_OWNER_USER_ID "'",
"percentageOwnership": 25
},
{
"role": "controlPerson",
"identityId": "'"$CONTROL_PERSON_USER_ID"'"
}
]
}'
Step Result
For each person, BitGo returns an associatedPersonId, a status, and a missingRequirements array, which specifies their required KYB information.
{
"type": "business",
"id": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"associatedPeople": [
{
"associatedPersonId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"role": "beneficialOwner",
"identityId": "f56a207c-0c96-4e5d-b59d-5bcf8092580a",
"userId": "68cc1bc8b1b5017f12c5c1e3c04cd1d4",
"percentageOwnership": 25,
"status": "missingRequirements",
"missingRequirements": [
{ "kind": "data", "name": "countryOfResidence", "status": "missing" }
]
},
{
"associatedPersonId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"role": "controlPerson",
"identityId": "df114ee7-7dc9-431e-aeae-fe4294f789cc",
"userId": "68cc1bca2f1d047e21d6c2f4d15de2e5",
"status": "missingRequirements",
"missingRequirements": [
{ "kind": "data", "name": "countryOfResidence", "status": "missing" }
]
}
]
}
4.3 Update Associated Persons with Location Information
Submit each person's location before any other personal information. BitGo uses countryOfResidence or countryOfCitizenship to generate the requirements for that person.
Repeat this step for each associated person.
Endpoint: Update KYB Identity
export INDIVIDUAL_IDENTITY_ID="<YOUR_INDIVIDUAL_IDENTITY_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X PATCH \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$INDIVIDUAL_IDENTITY_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"individual": {
"countryOfResidence": "USA",
"countryOfCitizenship": "USA"
}
}'
Step Result
The requirements array returns all the KYB information that you must submit in the following step.
{
"type": "individual",
"userId": "68cc1bc8b1b5017f12c5c1e3c04cd1d4",
"id": "df114ee7-7dc9-431e-aeae-fe4294f789cc",
"individual": {
"countryOfResidence": "USA",
"countryOfCitizenship": "USA"
},
"requirements": [
{ "kind": "data", "name": "nameFirst", "status": "missing" },
{ "kind": "data", "name": "nameLast", "status": "missing" },
{ "kind": "data", "name": "birthdate", "status": "missing" },
{ "kind": "data", "name": "identificationNumber", "status": "missing" },
{ "kind": "data", "name": "phoneNumber", "status": "missing" },
{ "kind": "data", "name": "occupation", "status": "missing" },
{ "kind": "data", "name": "address", "status": "missing" },
{ "kind": "data", "name": "politicallyExposedPerson", "status": "missing" }
],
"finalizeSubmission": false
}
4.4 Update Individual Identities with Required Information
TODO: Is this the associatedPersonId from the associatedPeople array, or the identityId?
Using the individual identity ID, submit the following personal information for each associated person:
Required Identity Fields
| Field | Description |
|---|---|
nameFirst, nameLast |
Legal name |
email |
Email address |
birthdate |
Month, day, and year. Zero-pad single digits, for example "01". |
identificationNumber |
Government ID or Social Security number |
phoneNumber |
Phone number with country code |
occupation |
Current occupation |
countryOfResidence |
Country of residence |
countryOfCitizenship |
Country of citizenship |
address |
Residential address |
politicallyExposedPerson |
Politically exposed person status (true or false) |
Endpoint: Update KYB Identity
export INDIVIDUAL_IDENTITY_ID="<INDIVIDUAL_IDENTITY_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X PATCH \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$INDIVIDUAL_IDENTITY_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"individual": {
"nameFirst": "John",
"nameLast": "Doe",
"email": "john.doe@acme.com",
"birthdate": {
"month": "01",
"day": "01",
"year": "2000"
},
"identificationNumber": "12345678",
"phoneNumber": {
"countryCode": "1",
"phoneNumber": "5559876543"
},
"occupation": "Other",
"countryOfResidence": "USA",
"countryOfCitizenship": "USA",
"address": {
"street1": "123 4th St",
"city": "San Francisco",
"subdivision": "CA",
"zip": "94103",
"country": "USA"
},
"politicallyExposedPerson": false
}
}'
Step Result
{
"type": "individual",
"userId": "68cc1bc8b1b5017f12c5c1e3c04cd1d4",
"id": "df114ee7-7dc9-431e-aeae-fe4294f789cc",
"requestedProducts": [],
"requirements": [
{
"kind": "data",
"name": "nameFirst",
"status": "submitted"
},
{
"kind": "data",
"name": "nameLast",
"status": "submitted"
},
{
"kind": "data",
"name": "birthdate",
"status": "submitted"
},
{
"kind": "data",
"name": "identificationNumber",
"status": "submitted"
},
{
"kind": "data",
"name": "politicallyExposedPerson",
"status": "submitted"
}
],
"finalizeSubmission": false
}
4.5 Remove an Associated Person (Optional)
You can remove an associated person before finalizing the KYB submission if both of the following are true:
- The business status for
requestedProductsisn'tinReview,approved, orrejected. - The individual's status isn't
inReview,verified, orrejected.
Endpoint: Remove Associated Person
export BUSINESS_IDENTITY_ID="<BUSINESS_IDENTITY_ID>"
export ASSOCIATED_PERSON_ID="<ASSOCIATED_PERSON_ID>" # associatedPersonId from associatedPeople array - not identityId
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X DELETE \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$BUSINESS_IDENTITY_ID/associated-people/$ASSOCIATED_PERSON_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Step Result
Returns the updated business identity with the removed person no longer present in the associatedPeople array and product statuses recalculated to reflect the updated associated person set.
{
"type": "business",
"id": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"associatedPeople": [
{
"associatedPersonId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"role": "controlPerson",
"identityId": "df114ee7-7dc9-431e-aeae-fe4294f789cc"
}
],
"requestedProducts": [
{
"name": "Trade",
"bitgoOrg": "BitGo Trust",
"status": "missingRequirements"
}
]
}
5. Upload Required Documents
Upload the required documents for KYB verification. For each required document you must generate an upload URL, upload the document, and then verify it.
Note
Evidence of legal status must be issued within the last 12 months. Accepted examples include a Certificate of Good Standing, a business registration or trade license, and a company registry extract.
5.1 Identify Business Type and Documents
For the exact documents you must upload, see the requirements array you received in Step 3.2, specifically, entries with kind: "document".
Every file must be a PDF, JPEG, PNG, HEIC, HEIF, or TIFF. When a document has more than one possible documentType, the requirements array specifies the exact file type to use.
5.2 Generate Document Upload URL
Generate an upload URL for each document.
Endpoint: Generate KYB Document Upload URL
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X POST \
"https://app.bitgo-test.com/api/document-service/v1/documents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"documentType": "w9"
}'
Step Result
Save the documentId and the uploadUrl.
Note
The uploadUrl points to the BitGo managed document storage provider, not to the BitGo API host. This is expected. The URL is single-use and expires at expiresAt. Upload directly to it.
{
"documentId": "c7c00bb6-0ad3-470d-83f3-a96ce043d812",
"documentType": "w9",
"documentTypeLabel": "W9 Form",
"subType": null,
"status": "awaitingUpload",
"files": [
{
"fileId": "c6c8651e-dbd3-4f35-ad4d-b3ed1c742a6b",
"fileView": "full",
"label": "W9 Form Document",
"required": true,
"uploadUrl": "https://api.withcortex.ai/public/apps/files/uploads/up_6B1Re7PtUzgzSimXdygEx3",
"expiresAt": "2025-10-18T16:09:23.973Z"
}
]
}
5.3 Upload Document
Upload your file to the URL from the previous step.
The CONTENT_TYPE value is optional. If you pass it, the file must resolve to one of the allowed types: application/pdf, image/jpeg, image/png, image/heic, image/heif, or image/tiff. You can't pass application/octet-stream.
export UPLOAD_URL="<DOCUMENT_UPLOAD_URL>"
export FILE_PATH="</path/to/your/document.pdf>"
export CONTENT_TYPE="application/pdf"
curl -X POST "$UPLOAD_URL" \
-F "file=@$FILE_PATH;type=$CONTENT_TYPE"
Step Result
{
"id": "afile_1jGYRK9FwcQ7mrPETfS3o6",
"file_id": "486674b3064254a7e3fa45f4314dbef7-fd377b79ef89f05782976d41f3f5aa9",
"file_filename": "w9.pdf",
"file_size": 140815,
"file_mimetype": "application/pdf",
"file_status": "PROCESSED",
"created_at": "2025-09-18T16:19:07.894Z"
}
5.4 Verify Document
Verify the document with its documentId.
Endpoint: Verify KYB Document Status
export DOCUMENT_ID="<YOUR_DOCUMENT_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X POST \
"https://app.bitgo-test.com/api/document-service/v1/documents/$DOCUMENT_ID/verify" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{}'
Step Result
{
"documentId": "c7c00bb6-0ad3-470d-83f3-a96ce043d812",
"documentType": "w9",
"documentTypeLabel": "W9 Form",
"status": "uploaded",
"files": [
{
"fileId": "c6c8651e-dbd3-4f35-ad4d-b3ed1c742a6b",
"fileView": "full",
"required": true,
"status": "uploaded"
}
]
}
5.5 Associate Documents with Identity
Associate each verified document with the correct identity. Use the business identity ID for business documents. Use the individual identity ID for individual documents. Add documentSubType when the document type has one. For example, a government ID uses a sub-type such as pp for a passport.
Endpoint: Assign KYB Document to Identity
export IDENTITY_ID="<YOUR_IDENTITY_ID>"
export DOCUMENT_ID="<YOUR_DOCUMENT_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X POST \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$IDENTITY_ID/documents" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"documents": [
{
"documentId": "'"$DOCUMENT_ID"'",
"documentType": "w9",
"documentSubType": null
}
]
}'
Step Result
Save the id in acceptedDocuments. If you replace the document later, you must pass this ID.
{
"identityId": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"acceptedDocuments": [
{
"id": "3a83bde3-6db8-49f4-b3aa-7d38ecd1006c",
"documentId": "c7c00bb6-0ad3-470d-83f3-a96ce043d812",
"documentType": "w9",
"status": "submitted",
"createdAt": "2025-09-18T16:25:52.045Z",
"updatedAt": "2025-09-18T16:25:52.045Z"
}
],
"rejectedDocuments": []
}
5.6 Update Document Association (Optional)
If you make a mistake, you can replace an uploaded document - you don't need to remove and re-add it.
Repeat the following steps:
Then update the association using the following:
Endpoint: Update KYB Document
export IDENTITY_ID="<YOUR_IDENTITY_ID>"
export IDENTITY_DOCUMENT_ID="<IDENTITY_DOCUMENT_ID>" # id from acceptedDocuments array in step 5.5
export NEW_DOCUMENT_ID="<NEW_DOCUMENT_SERVICE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X PUT \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$IDENTITY_ID/documents/$IDENTITY_DOCUMENT_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"documentId": "'"$NEW_DOCUMENT_ID"'",
"documentType": "w9"
}'
Step Result
{
"id": "3a83bde3-6db8-49f4-b3aa-7d38ecd1006c",
"documentId": "d8e00cc7-1be4-581e-94g4-b07df154e923",
"documentType": "w9",
"status": "submitted",
"createdAt": "2025-09-18T16:25:52.045Z",
"updatedAt": "2025-09-18T16:35:12.011Z"
}
6. Check Statuses
Fetch each identity (business and individuals) to see if any requirements are still missing.
Endpoint: Get KYB Identity
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
export IDENTITY_ID="<BUSINESS_IDENTITY_ID>"
curl -X GET \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$IDENTITY_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Step Result
Ensure all fields in the following arrays are ready for BitGo review:
| Array | Requirements |
|---|---|
requestedProducts[] |
"status": "readyForSubmission" |
associatedPeople[] |
|
requirements[] |
"status": "submitted" |
documents[] |
"status": "submitted" |
If you have any outstanding requirements, you can:
- Add missing information by calling the Update KYB Identity endpoint.
- Upload missing documents by following Step 5.
7. Finalize Submission
Once all statuses are ready and all supporting documentation is uploaded, finalize the KYB submission, marking it ready for review by BitGo.
Important
Finalization is permanent. Ensure all information is complete before proceeding. Once submitted, you can no longer update the identity.
Endpoint: Update KYB Identity
export IDENTITY_ID="<BUSINESS_IDENTITY_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X PATCH \
"https://app.bitgo-test.com/api/identity-service/v1/identities/$IDENTITY_ID" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"finalizeSubmission": true
}'
Step Result
BitGo returns the business identity with:
"finalizeSubmission": "true".- Each requirement is
submitted. - Each requested product moves to
inReview.
The business identity is now under review by BitGo. If additional information is required, BitGo contacts you — not your end user.
Note
If you receive any values with missing or if the missingRequirements array has objects, then BitGo didn't accept the finalized submission. Supply the missing information and try again.
{
"type": "business",
"id": "c1ecba6b-0914-4bc3-ae67-4188e061aa3e",
"requestedProducts": [
{
"name": "Trade",
"bitgoOrg": "BitGo Trust",
"status": "inReview"
},
{
"name": "Go Account",
"bitgoOrg": "BitGo Trust",
"status": "inReview"
}
],
"requirements": [
{ "kind": "document", "name": "certificateOfIncorporation", "status": "submitted" },
{ "kind": "document", "name": "proofOfAuthorizedSignatories", "status": "submitted" },
{ "kind": "businessInformation", "name": "businessName", "status": "submitted" },
{ "kind": "businessInformation", "name": "amlAttestation", "status": "submitted" },
{ "kind": "associatedPerson", "name": "controlPeople", "status": "submitted" }
],
"associatedPeople": [
{
"associatedPersonId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"role": "controlPerson",
"identityId": "df114ee7-7dc9-431e-aeae-fe4294f789cc",
"status": "inReview",
"missingRequirements": []
}
],
"finalizeSubmission": true
}
8. Sign Contracts
Before BitGo activates the enterprise, you must sign the following contracts in two separate calls:
master-agreement(which includes includestrade-mpa,custody-sa, andstaking-sa)distributed-custody-mic
Endpoint: Sign a Contract for an Enterprise Within an Organization
export ORGANIZATION_ID="<YOUR_ORGANIZATION_ID>"
export ENTERPRISE_ID="<YOUR_ENTERPRISE_ID>"
export ACCESS_TOKEN="<SERVICE_USER_ACCESS_TOKEN>"
curl -X POST \
"https://app.bitgo-test.com/api/v2/organization/$ORGANIZATION_ID/enterprise/$ENTERPRISE_ID/contract" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{
"contractType": "master-agreement",
"signedDate": "2026-09-09T18:47:23"
}'
Step Result
{
"success": true,
"contractsSigned": [
{
"contractType": "master-agreement",
"signedBy": "string",
"signedDate": "string",
"ip": "string"
}
],
"message": "string"
}
Next Steps
Create Go Accounts for your end users.
See Also
- API Reference: Add a User to an Enterprise Within an Organization
- API Reference: Assign KYB Document to Identity
- API Reference: Create an Enterprise for an Organization
- API Reference: Create KYB Identity
- API Reference: Generate KYB Document Upload URL
- API Reference: Get KYB Identity
- API Reference: Remove Associated Person
- API Reference: Sign a Contract for an Enterprise Within an Organization
- API Reference: Update KYB Document
- API Reference: Update KYB Identity
- API Reference: Verify KYB Document Status