Company Verification (KYC)
Company Verification (KYC) is the regulatory check on a company's business legitimacy and ownership. It can run at any time, including alongside Company Bank Setup.
If KYC isn't enabled in your environment, you can skip this flow entirely.
Before you submit KYC for review
Three things must be in place before you can submit KYC for review:
- A signatory. The company must have a signatory. See Company Signatories.
- The required documents. Every required company and signatory document must be uploaded (Steps 4 and 5 below).
- Bank Setup, if a bank provider is enabled. If a bank provider is enabled for the company, KYC can't be submitted for review until Bank Setup reports a
Completedstatus.
Two ways to call these APIs
As with Bank Setup, every step below can be done either by calling a function from the @worklio/wep package or by calling the underlying REST endpoint directly.
@worklio/wep functions such as wepGetCompanyKYC don't make network requests themselves — they return a descriptor (method, url, and optionally createRequestBody/useResponseBody) that you execute yourself, for example with fetch. See Company Bank Setup: Two ways to call these APIs for the full explanation and a reusable callWepApi helper.
Prerequisites
| Requirement | Description |
|---|---|
| FEIN | The company's Federal Employer Identification Number must be valid and registered before onboarding begins. |
| Company ID | Required for every call below. Returned as id when you create the company. |
| Signatory | The company must have a signatory before KYC can be submitted for review. See Company Signatories. |
| Authorization | Only administrative roles can call these endpoints. |
Company Verification flow
Step 1: Get the KYC summary
Fetch the company's current KYC status along with the business and ownership fields already on file: business name, FEIN, address, ownership info, and KYC status.
- wep:
wepGetCompanyKYC(companyId) - Endpoint:
GET /wep/companies/{companyId}/kyc
require("dotenv").config();
const TOKEN = process.env.API_KEY
const CLIENT_ID = process.env.CLIENT_ID
const URL = process.env.URL
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc
`
async function getKYC() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
getKYC();{
status: 0
}This same call is used again at the end of the flow (Step 9) to confirm completion.
Step 2: List company KYC documents
Retrieve the documents already uploaded for the company, and their status.
- wep:
wepGetCompanyKYCDocuments(companyId) - Endpoint:
/wep/companies/{clientId}/kyc/documents
require("dotenv").config();
const TOKEN = process.env.API_KEY
const CLIENT_ID = process.env.CLIENT_ID
const URL = process.env.URL
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/documents
`
async function listMyKYCDocuments() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
listMyKYCDocuments();[]Step 3: Make sure the company has a signatory
KYC can't be submitted for review unless the company has a signatory. Check whether one exists.
- wep:
wepGetSignatories(companyId) - Endpoint:
GET https://api.worklio.com/wep/companies/{companyId}/kyc/signatories
require("dotenv").config();
const TOKEN = process.env.API_KEY_BENEFIT;
const CLIENT_ID = process.env.CLIENT_ID_BENEFIT;
const URL = process.env.URL_BENEFIT;
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/signatories`;
async function getSignatories() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"x-api-version": "2.0",
"content-type": "application/json",
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
getSignatories()[
{
"id": 7,
"type": 3,
"status": 1,
"gender": 2,
"firstName": "John",
"lastName": "Doe",
"middleName": "",
"ownership": 100
}
]If the list is empty, add a signatory before you continue. Adding, updating, and removing signatories, and managing the documents on file for each signatory, are covered in Company Signatories.
Step 4: Get required document types
Get the list of required document types. The endpoint returns documents for one scope at a time, so call it once for the company and once for its signatories:
-
wep:
wepGetCompanyKYCDocumentTypes({ companyId, documentScope }) -
Endpoint:
GET https://api.worklio.com/wep/companies/{companyId}/kyc/documenttypes
require("dotenv").config();
const TOKEN = process.env.API_KEY
const CLIENT_ID = process.env.CLIENT_ID
const URL = process.env.URL
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/documenttypes
`
async function getRequiredDocumentTypes() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
getRequiredDocumentTypes();[
{
"key": "EIN_DOC",
"name": "EIN Document - Form 147C",
"description": "Image of Form 147C issued to the business by the IRS.",
"scope": 1,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
},
{
"key": "SS4_DOC",
"name": "EIN Application - Form SS4",
"description": "Image of Form SS4 that is used by a business to apply for a TIN number.",
"scope": 1,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
}
]Without scope, the response contains company documents only. It never includes signatory documents. For the signatory response and the rules for choosing which documents to upload, see Company Signatories.
Compare the company list against the documents from Step 2, and the signatory list against the signatory's documents, to determine which documents are still missing.
Same as with signatories only one of the documents needs to be uploaded.
Step 5: Upload required documents
Upload each required document. Uploading documents for a signatory is covered in Company Signatories.
- wep:
wepCreateCompanyKYCDocument(companyId) - Endpoint:
POST /wep/companies/{clientId}/kyc/documents
require("dotenv").config();
const fs = require("fs");
const path = require("path");
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const URL = process.env.URL;
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/documents`;
const filePath = path.join(__dirname, "SS4_DOC_MY_COMPANY.pdf");
async function uploadKYC() {
const fileBuffer = fs.readFileSync(filePath);
const fileName = path.basename(filePath);
const form = new FormData();
form.append("Document[0].Key", "SS4_DOC");
form.append(
"Document[0].File",
new Blob([fileBuffer], { type: "application/pdf" }),
fileName
);
form.append("Key", "SS4_DOC")
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"x-api-version": "2.0",
// do NOT set content-type manually — fetch adds the correct
// multipart/form-data boundary for you
},
body: form,
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
uploadKYC()trueStep 6: Save or update KYC information
Save the business and ownership information collected in Steps 1–5.
- wep:
wepSaveCompanyKYC(companyId) - Endpoint:
/wep/companies/{clientId}/kyc
require("dotenv").config();
const TOKEN = process.env.API_KEY
const CLIENT_ID = process.env.CLIENT_ID
const SIGNATORY_ID = process.env.SIGNATORY_ID
const URL = process.env.URL
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc
`
const payload = {
startOn: "2027-01-01",
primaryControllingContactSignatoryId: SIGNATORY_ID,
complianceContactSignatoryId: SIGNATORY_ID,
bankingSignatoryId: SIGNATORY_ID,
moneyTransmissionLicense: true,
involvedWithCryptocurrency: false,
gamblingBusiness: false,
registeredWithSecurities: true,
regularFinanacialCompany: true,
ownedByPublicCompany: false,
publicCompany: true
}
async function saveKYC() {
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
saveKYC();{
"status": 1,
"trustLevel": 0,
"message": "",
"publicCompany": true,
"ownedByPublicCompany": false,
"regularFinanacialCompany": true,
"registeredWithSecurities": true,
"gamblingBusiness": false,
"involvedWithCryptocurrency": false,
"moneyTransmissionLicense": true,
"bankingSignatoryId": 4,
"complianceContactSignatoryId": 4,
"primaryControllingContactSignatoryId": 4,
"startOn": "2027-01-01T00:00:00Z"
}Step
Step 7: Submit KYC for review
Once every required field and document is in place and the company has a signatory, submit for review.
- wep:
wepSaveCompanyKYC(companyId) - Endpoint:
/wep/companies/{clientId}/kyc/process
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const URL = process.env.URL;
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/process
`
const payload = {
trustLevel: 3,
}
async function submitForReview() {
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
submitForReview();trueStep 8: Verify Company
Verify the company.
- wep:
wepSaveCompanyKYC(companyId) - Endpoint:
/wep/companies/{clientId/kyc/verify
require("dotenv").config();
const TOKEN = process.env.API_KEY_BENEFIT;
const CLIENT_ID = process.env.CLIENT_ID_BENEFIT;
const URL = process.env.URL_BENEFIT;
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/verify
`
const payload = {
status: 3,
verifyAllDocuments: true,
verifyAllSignatories: true
}
async function verifyKYC() {
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
verifyKYC();trueStep 9: Confirm completion
Check that KYC and document statuses are both complete before enabling payroll.
- wep:
wepGetCompanyKYC(companyId),wepGetCompanyKYCDocuments(companyId) - Endpoint: same calls as Steps 1 and 2.
KYC verification status
| Value | Meaning |
|---|---|
None | No verification has started. |
Pending | Verification has been submitted and is awaiting a decision. |
Completed | Verification is complete. |
Function reference
| Domain | Purpose | wep function | Method |
|---|---|---|---|
| Company KYC | Get KYC summary | wepGetCompanyKYC(companyId) | GET |
| Company KYC | Save/update KYC data | wepSaveCompanyKYC(companyId) | POST |
| KYC Documents | List company docs | wepGetCompanyKYCDocuments(companyId) | GET |
| KYC Documents | Get document detail | wepGetCompanyKYCDocumentDetail({ companyId, documentId }) | GET |
| KYC Documents | Get required doc types | wepGetCompanyKYCDocumentTypes({ companyId, documentScope }) | GET |
| KYC Documents | Get doc configuration | wepGetCompanyKYCDocumentConfigurations({ companyId, documentKey }) | GET |
| KYC Documents | Upload documents | wepCreateCompanyKYCDocument(companyId) | POST |
Signatory functions are listed in Company Signatories.
Glossary
| Term | Definition |
|---|---|
| KYC | The regulatory process that verifies a business's legitimacy and ownership. |
| Signatory | A person who signs for the company. A company needs one before KYC can be submitted for review. See Company Signatories. |
| Beneficial Owner | An individual with significant control or authority over the company — collected as part of ownership info in Steps 1 and 6. |
Enabling payroll
Payroll can only be enabled once KYC reports Completed (or is disabled for this environment) and Company Bank Setup reports Completed. Record the timestamp each track completes — you'll want it for audits and support.
Error handling and edge cases
- Only users with administrative privileges should call these endpoints.
GET /kyc/documenttypesreturns company documents unless you passscope=2. Call it for both scopes to get the full list.
Updated about 2 hours ago
