Company Signatories
A signatory is a person who signs for the company. KYC can't be submitted for review unless the company has a signatory and the required signatory documents are uploaded. See Company Verification (KYC).
Add the signatory early in onboarding so KYC isn't blocked later.
Two ways to call these APIs
As with KYC and 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. The package's functions return a request descriptor that you execute yourself. See Company Verification (KYC): Two ways to call these APIs for how that works.
Prerequisites
| Requirement | Description |
|---|---|
| Company ID | Required for every call below. Returned as id when you create the company. |
| Authorization | Only administrative roles can call these endpoints. |
The signatory object
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier of the signatory. Save it: it is the signatoryId path parameter in the endpoints below. |
type | integer | [ClientAdmin, Employee, External] 1-3 |
status | integer | [None-0, Read-1, Processing-2, Verified-3, Rejected-4, Error-9, AutoProcessing-11, AutoProcessed-12] |
trustLevel | integer | [None, Low, Medium, High] 0-3 |
gender | integer | [Female, Male, Other] 1-3 |
firstName | string | First name. |
middleName | string | Middle name. Empty string if none. |
lastName | string | Last name. |
birthOn | string | Date of birth, as an ISO 8601 timestamp. |
ssn | string | Social Security number. |
email | string | Email address. |
phone | string | Phone number. Returned in the format +1 (201) 548-9854. |
ownership | number | Percentage of the company the signatory owns. Returned by add and update, and by get when set. |
position | string | The signatory's position in the company. Returned by get, add, and update only. |
message | string | Returned by get only. |
address | object | The signatory's address. See below. Returned by get, add, and update only. |
List returns a shorter object: id, type, status, gender, firstName, lastName, and middleName.
Address object
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier of the address. |
addressLine1 | string | Street address. |
addressLine2 | string | Apartment, suite, or unit. Empty string if none. |
addressCity | string | City. |
addressState | string | Two-letter state code, for example NC. |
addressZIP | string | ZIP code. |
addressCountry | string | Country code. Returned as US in every example. |
Signatory flow
Step 1: List the company's signatories
Retrieve every signatory on file for the company. Use this to check whether the company already has one before you add another.
- wep:
wepGetSignatories(companyId) - Endpoint:
GET /wep/companies/{companyId}/kyc/signatories
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories`;
async function listSignatories() {
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));
}
listSignatories();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response:
[
{
"id": 4,
"type": 3,
"status": 3,
"gender": 2,
"firstName": "Alex",
"lastName": "Morgan",
"middleName": ""
}
]Step 2: Get a signatory
Retrieve a single signatory with its full details.
- wep:
wepGetSignatory({ companyId, signatoryId }) - Endpoint:
GET wep/companies/{companyId}/kyc/signatories/{signatoryId}
| Parameter | Type | Required | Description |
|---|---|---|---|
companyId | integer | Yes | The company's id. Path parameter. |
signatoryId | integer | Yes | The signatory's id, as returned by Step 1 or Step 3. Path parameter. |
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const SIGNATORY_ID = 4;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories/${SIGNATORY_ID}`;
async function getSignatory() {
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));
}
getSignatory();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories/4" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response:
{
"id": 4,
"trustLevel": 3,
"type": 3,
"status": 3,
"gender": 2,
"firstName": "Alex",
"lastName": "Morgan",
"middleName": "",
"birthOn": "1980-04-06T00:00:00Z",
"ssn": "123456789",
"email": "[email protected]",
"phone": "+1 (548) 215-3647",
"position": "",
"message": "",
"address": {
"id": 397,
"addressLine1": "350 5th Ave",
"addressLine2": "",
"addressCity": "New York",
"addressState": "NY",
"addressZIP": "10118",
"addressCountry": "US"
}
}Step 3: Add a signatory
Add a signatory to the company.
- wep:
wepCreateSignatory({ companyId }) - Endpoint:
POST /wep/companies/{companyId}/kyc/signatories
Fields
| Field | Type | Required | Description |
|---|---|---|---|
gender | integer | Yes | [Female, Male, Other] 1-3 |
firstName | string | Yes | First name. |
lastName | string | Yes | Last name. |
birthOn | string | Yes | Date of birth, as YYYY-MM-DD. |
ssn | string | Yes | Social Security number, for example 123-45-6789. |
email | string | Yes | Email address. |
phone | string | Yes | Phone number, digits only, for example 2015489854. |
ownership | string | No | Percentage of the company the signatory owns, for example "100". The response returns it as a number. |
addressLine1 | string | Yes | Street address. |
addressCity | string | Yes | City. |
addressState | string | Yes | Two-letter state code. |
addressZIP | string | Yes | ZIP code. |
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories`;
const payload = {
gender: 1,
firstName: "John",
lastName: "Doe",
birthOn: "1985-03-12",
ssn: "123-45-6789",
email: "[email protected]",
phone: "2015489854",
ownership: "100",
addressLine1: "969 Cox Rd",
addressCity: "Gastonia",
addressState: "NC",
addressZIP: "28054"
};
async function createSignatory() {
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));
}
createSignatory();curl -s -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" \
-d '{
"gender": 1,
"firstName": "John",
"lastName": "Doe",
"birthOn": "1985-03-12",
"ssn": "123-45-6789",
"email": "[email protected]",
"phone": "2015489854",
"ownership": "100",
"addressLine1": "969 Cox Rd",
"addressCity": "Gastonia",
"addressState": "NC",
"addressZIP": "28054"
}' | jq .Example response:
{
"id": 7,
"trustLevel": 0,
"type": 3,
"status": 1,
"gender": 1,
"firstName": "John",
"lastName": "Doe",
"middleName": "",
"birthOn": "1985-03-12T00:00:00Z",
"ssn": "123-45-6789",
"email": "[email protected]",
"phone": "+1 (201) 548-9854",
"ownership": 100,
"position": "",
"address": {
"id": 437,
"addressLine1": "969 Cox Rd",
"addressLine2": "",
"addressCity": "Gastonia",
"addressState": "NC",
"addressZIP": "28054",
"addressCountry": "US"
}
}Save id. You need it to update or remove the signatory and to manage the signatory's documents.
Step 4: Update a signatory
Change the details of an existing signatory. Send only the fields you want to change. Fields you leave out keep their current value. The response returns the full updated signatory.
- wep:
wepUpdateSignatory({ companyId, signatoryId }) - Endpoint:
PATCH /wep/companies/{companyId}/kyc/signatories/{signatoryId}
This example corrects the signatory's birthOn.
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const SIGNATORY_ID = 7;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories/${SIGNATORY_ID}`;
const payload = {
birthOn: "1985-03-21"
};
async function updateSignatory() {
const response = await fetch(url, {
method: "PATCH",
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));
}
updateSignatory();curl -s -X PATCH "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories/7" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" \
-d '{
"birthOn": "1985-03-21"
}' | jq .Example response:
{
"id": 7,
"trustLevel": 0,
"type": 3,
"status": 1,
"gender": 1,
"firstName": "John",
"lastName": "Doe",
"middleName": "",
"birthOn": "1985-03-21T00:00:00Z",
"ssn": "123-45-6789",
"email": "[email protected]",
"phone": "+1 (201) 548-9854",
"ownership": 100,
"position": "",
"address": {
"id": 437,
"addressLine1": "969 Cox Rd",
"addressLine2": "",
"addressCity": "Gastonia",
"addressState": "NC",
"addressZIP": "28054",
"addressCountry": "US"
}
}Step 5: Remove a signatory
Remove a signatory from the company. A successful call returns 204 with no body.
- wep:
wepRemoveSignatory({ companyId, signatoryId }) - Endpoint:
DELETE /wep/companies/{companyId}/kyc/signatories/{signatoryId}
If you remove the company's only signatory, add another before you submit KYC for review.
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const SIGNATORY_ID = 4;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories/${SIGNATORY_ID}`;
async function removeSignatory() {
const response = await fetch(url, {
method: "DELETE",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
}
});
console.log(response.status); // 204, no body
}
removeSignatory();curl -s -o /dev/null -w "%{http_code}\n" -X DELETE "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories/4" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0"Example response:
No bodySignatory documents
KYC requires documents for the company and for each signatory. This section covers the signatory side. Company documents are covered in Company Verification (KYC).
For each signatory:
- Get the document types you can upload (Get the document types).
- Check the details of the type you chose, because some types need more than one upload (Get the details of a document type).
- Upload the document or documents (Upload a signatory document).
- List the signatory's documents to check what's on file (List a signatory's documents).
Get the document types
Get the document types for signatories.
- wep:
wepGetCompanyKYCDocumentTypes({ companyId, documentScope }) - Endpoint:
GET https://api.worklio.com/wep/companies/{companyId}/kyc/documenttypes?scope=2
| Parameter | Type | Required | Description |
|---|---|---|---|
companyId | integer | Yes | The company's id. Path parameter. |
scope | integer | No | Which documents to return. Without scope, the call returns company documents only. Use 2 to get signatory documents. |
Withoutscope=2, this endpoint returns company documents only. It never includes signatory documents unless you passscope=2.
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/documenttypes?scope=2`;
async function getSignatoryDocumentTypes() {
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));
}
getSignatoryDocumentTypes();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/documenttypes?scope=2" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response:
[
{
"key": "PASS_DOC",
"name": "Passport Card",
"description": "Photo ID and limited travel card issued by the relevant government authority.",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
},
{
"key": "PHOTO_ID",
"name": "Photo Id",
"description": "A government issued photo ID (driver's license, state ID, or passport)",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
},
{
"key": "INTERNATIONAL_PHOTO_ID",
"name": "International Photo Id",
"description": "A government issued photo ID (driver's license, state ID, or passport) that is not in English",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
},
{
"key": "DRIVER_LICENSE",
"name": "Driver's License",
"description": "Photo ID and authorization to operate a vehicle issued by the relevant government authority",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
}
]| Field | Type | Description |
|---|---|---|
key | string | Identifier of the document type. Use it as {key} in Get the details of a document type. |
name | string | Display name of the document type. |
description | string | What the document is. |
scope | integer | The scope this type belongs to. 2 is signatory. |
isFile | boolean | Whether the document is uploaded as a file. |
fileTypes | string | Comma-separated list of accepted file types, for example png,jpg,jpeg,pdf. |
isSecondary | boolean | true if this entry is an additional upload that belongs to another document type. |
keyPrimary | string | For a secondary entry, the key of the document type it belongs to. Absent on primary entries. |
trustLevel | integer | [None, Low, Medium, High] 0-3 |
isRequired | boolean | Returned as true for every type in the example above. |
Every type in this response hasisRequired: true, but you only need to upload one of the document types for each signatory.
Get the details of a document type
Some document types need more than one upload. Call this endpoint for the type you chose, before you upload, to see every upload it needs.
- wep:
wepGetCompanyKYCDocumentConfigurations({companyId, documentKey}) - Endpoint:
GET https://api.worklio.com/wep/companies/{companyId}/kyc/documenttypes/{key}
| Parameter | Type | Required | Description |
|---|---|---|---|
companyId | integer | Yes | The company's id. Path parameter. |
key | string | Yes | The document type's key, for example PHOTO_ID. Path parameter. |
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const DOCUMENT_KEY = "PHOTO_ID";
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/documenttypes/${DOCUMENT_KEY}`;
async function getDocumentType() {
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));
}
getDocumentType();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/documenttypes/PHOTO_ID" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response:
[
{
"key": "PHOTO_ID",
"name": "Photo Id",
"description": "A government issued photo ID (driver's license, state ID, or passport)",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": false,
"trustLevel": 0,
"isRequired": true
},
{
"key": "PHOTO_ID2",
"name": "Photo Id Next Page",
"description": "A government issued photo ID (driver's license, state ID, or passport)",
"scope": 2,
"isFile": true,
"fileTypes": "png,jpg,jpeg,pdf",
"isSecondary": true,
"keyPrimary": "PHOTO_ID",
"trustLevel": 0,
"isRequired": true
}
]In this example, PHOTO_ID needs two uploads: PHOTO_ID itself and PHOTO_ID2 ("Photo Id Next Page"). PHOTO_ID2 has isSecondary: true and keyPrimary: "PHOTO_ID".
Upload a signatory document
- wep:
wepCreateSignatoryKYCDocument({companyId, signatoryId}) - Endpoint:
wep/companies/{clientId}/kyc/signatories/{signatoryId}/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 SINGATORY_ID = process.env.SIGNATORY_ID
const URL = process.env.URL;
const url = `${URL}/wep/companies/${CLIENT_ID}/kyc/signatories/${SIGNATORY_ID}/documents`;
const filePath1 = path.join(__dirname, "PHOTO_ID.pdf");
const filePath2 = path.join(__dirname, "PHOTO_ID2.pdf")
async function uploadSignatoryDocuments() {
const fileBuffer1 = fs.readFileSync(filePath1);
const fileName1 = path.basename(filePath1);
const fileBuffer2 = fs.readFileSync(filePath2);
const fileName2 = path.basename(filePath2);
const form = new FormData();
form.append("Document[0].Key", "PHOTO_ID");
form.append(
"Document[0].File",
new Blob([fileBuffer1], { type: "application/pdf" }),
fileName1
);
form.append("Document[1].Key", "PHOTO_ID2");
form.append(
"Document[1].File",
new Blob([fileBuffer2], { type: "application/pdf" }),
fileName2
);
form.append("Key", "PHOTO_ID")
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));
}
uploadSignatoryDocuments()curl -s -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories/7/documents" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "x-api-version: 2.0" \
-F "Document[0].Key=PHOTO_ID" \
-F "Document[0].File=@PHOTO_ID.pdf;type=application/pdf" \
-F "Document[1].Key=PHOTO_ID2" \
-F "Document[1].File=@PHOTO_ID2.pdf;type=application/pdf" \
-F "Key=PHOTO_ID" | jq .Example response:
trueCompany documents are uploaded with wepCreateCompanyKYCDocument(companyId) using multipart/form-data. See Step 5 in Company Verification (KYC).
List a signatory's documents
Retrieve the documents on file for a signatory, and their status. A signatory with no uploaded documents returns an empty array.
- wep:
wepGetSignatoryDocuments({ companyId, signatoryId }) - Endpoint:
GET https://api.worklio.com/wep/companies/{companyId}/kyc/signatories/{signatoryId}/documents
Example request:
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const SIGNATORY_ID = 7;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/kyc/signatories/${SIGNATORY_ID}/documents`;
async function listSignatoryDocuments() {
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));
}
listSignatoryDocuments();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/kyc/signatories/7/documents" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response:
[
{
"id": 19,
"key": "PHOTO_ID",
"name": "Photo Id",
"isFile": true,
"description": "A government issued photo ID (driver's license, state ID, or passport)",
"verifyStatus": 0
}
]Function reference
| Purpose | wep function | Method |
|---|---|---|
| List signatories | wepGetSignatories(companyId) | GET |
| Get signatory detail | wepGetSignatory({ companyId, signatoryId }) | GET |
| Add a signatory | wepCreateSignatory({ companyId }) | POST |
| Update signatory | wepUpdateSignatory({ companyId, signatoryId }) | PATCH |
| Remove signatory | wepRemoveSignatory({ companyId, signatoryId }) | DELETE |
| List signatory docs | wepGetSignatoryDocuments({ companyId, signatoryId }) | GET |
| Get document types | wepGetCompanyKYCDocumentTypes({ companyId, documentScope }) | GET |
Error handling and edge cases
- Only users with administrative privileges should call these endpoints.
- You can't submit KYC for review without a signatory or without the required documents.
GET /kyc/documenttypesreturns company documents unless you passscope=2.- Every signatory document type is returned with
isRequired: true, but you only need to upload one of the types for each signatory. Some types need more than one upload, so check the type's details first.
Updated about 2 hours ago
