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

RequirementDescription
Company IDRequired for every call below. Returned as id when you create the company.
AuthorizationOnly administrative roles can call these endpoints.

The signatory object

FieldTypeDescription
idintegerUnique identifier of the signatory. Save it: it is the signatoryId path parameter in the endpoints below.
typeinteger[ClientAdmin, Employee, External] 1-3
statusinteger[None-0, Read-1, Processing-2, Verified-3, Rejected-4, Error-9, AutoProcessing-11, AutoProcessed-12]
trustLevelinteger[None, Low, Medium, High] 0-3
genderinteger[Female, Male, Other] 1-3
firstNamestringFirst name.
middleNamestringMiddle name. Empty string if none.
lastNamestringLast name.
birthOnstringDate of birth, as an ISO 8601 timestamp.
ssnstringSocial Security number.
emailstringEmail address.
phonestringPhone number. Returned in the format +1 (201) 548-9854.
ownershipnumberPercentage of the company the signatory owns. Returned by add and update, and by get when set.
positionstringThe signatory's position in the company. Returned by get, add, and update only.
messagestringReturned by get only.
addressobjectThe 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

FieldTypeDescription
idintegerUnique identifier of the address.
addressLine1stringStreet address.
addressLine2stringApartment, suite, or unit. Empty string if none.
addressCitystringCity.
addressStatestringTwo-letter state code, for example NC.
addressZIPstringZIP code.
addressCountrystringCountry 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}
ParameterTypeRequiredDescription
companyIdintegerYesThe company's id. Path parameter.
signatoryIdintegerYesThe 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

FieldTypeRequiredDescription
genderintegerYes[Female, Male, Other] 1-3
firstNamestringYesFirst name.
lastNamestringYesLast name.
birthOnstringYesDate of birth, as YYYY-MM-DD.
ssnstringYesSocial Security number, for example 123-45-6789.
emailstringYesEmail address.
phonestringYesPhone number, digits only, for example 2015489854.
ownershipstringNoPercentage of the company the signatory owns, for example "100". The response returns it as a number.
addressLine1stringYesStreet address.
addressCitystringYesCity.
addressStatestringYesTwo-letter state code.
addressZIPstringYesZIP 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 body

Signatory 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:

  1. Get the document types you can upload (Get the document types).
  2. Check the details of the type you chose, because some types need more than one upload (Get the details of a document type).
  3. Upload the document or documents (Upload a signatory document).
  4. 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
ParameterTypeRequiredDescription
companyIdintegerYesThe company's id. Path parameter.
scopeintegerNoWhich documents to return. Without scope, the call returns company documents only. Use 2 to get signatory documents.
🚧

Without scope=2, this endpoint returns company documents only. It never includes signatory documents unless you pass scope=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
  }
]
FieldTypeDescription
keystringIdentifier of the document type. Use it as {key} in Get the details of a document type.
namestringDisplay name of the document type.
descriptionstringWhat the document is.
scopeintegerThe scope this type belongs to. 2 is signatory.
isFilebooleanWhether the document is uploaded as a file.
fileTypesstringComma-separated list of accepted file types, for example png,jpg,jpeg,pdf.
isSecondarybooleantrue if this entry is an additional upload that belongs to another document type.
keyPrimarystringFor a secondary entry, the key of the document type it belongs to. Absent on primary entries.
trustLevelinteger[None, Low, Medium, High] 0-3
isRequiredbooleanReturned as true for every type in the example above.
🚧

Every type in this response has isRequired: 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}
ParameterTypeRequiredDescription
companyIdintegerYesThe company's id. Path parameter.
keystringYesThe 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:

true

Company 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

Purposewep functionMethod
List signatorieswepGetSignatories(companyId)GET
Get signatory detailwepGetSignatory({ companyId, signatoryId })GET
Add a signatorywepCreateSignatory({ companyId })POST
Update signatorywepUpdateSignatory({ companyId, signatoryId })PATCH
Remove signatorywepRemoveSignatory({ companyId, signatoryId })DELETE
List signatory docswepGetSignatoryDocuments({ companyId, signatoryId })GET
Get document typeswepGetCompanyKYCDocumentTypes({ 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/documenttypes returns company documents unless you pass scope=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.

Did this page help you?