Skip to content

Call Dockt from TypeScript

Use Dockt from your TypeScript backend to check a worker’s details and documents. This guide uses Dockt’s OpenAPI description to generate request and response types, so your editor can check the API calls.

The example uses native fetch and a workspace credential. It creates an Assessment, the case for one worker, uploads a document, and reads the saved result, called a Decision.

In your own application project, make sure you have:

  • Node.js 20 or another server runtime with fetch, FormData, and Blob.
  • A workspace credential stored as DOCKT_API_TOKEN.
  • TypeScript configured for your backend.

Never expose DOCKT_API_TOKEN to browser or mobile code.

Generate a TypeScript declaration file from Dockt’s public OpenAPI URL:

Terminal window
npx openapi-typescript https://api.dockt.com/openapi.json \
--root-types \
--root-types-no-schema-prefix \
--output src/dockt-schema.d.ts

This command creates src/dockt-schema.d.ts in your project with the public request and response types.

Commit the generated file so you can review contract changes before updating your integration.

In your application, create src/dockt.ts:

import type {
Assessment,
CreateAssessmentBody,
Decision,
Document,
ProblemDetails
} from './dockt-schema';
type SingleEnvelope<T> = {
object: 'single';
data: T;
};
export class DocktApiError extends Error {
constructor(
readonly status: number,
readonly requestId: string | null,
readonly problem: ProblemDetails | null
) {
super(problem?.detail ?? `Dockt request failed with status ${status}.`);
}
}
export const createDocktClient = (token: string) => {
const request = async <T>(path: string, init: RequestInit = {}) => {
const headers = new Headers(init.headers);
headers.set('authorization', `Bearer ${token}`);
headers.set('accept', 'application/json');
const response = await fetch(new URL(path, 'https://api.dockt.com'), {
...init,
headers
});
const body = await response.json().catch(() => null);
if (!response.ok) {
throw new DocktApiError(
response.status,
response.headers.get('x-request-id'),
body as ProblemDetails | null
);
}
return body as T;
};
return {
async createAssessment(body: CreateAssessmentBody, idempotencyKey: string) {
const response = await request<SingleEnvelope<Assessment>>('/v1/assessments', {
method: 'POST',
headers: {
'content-type': 'application/json',
'idempotency-key': idempotencyKey
},
body: JSON.stringify(body)
});
return response.data;
},
async getAssessment(assessmentId: string) {
const response = await request<SingleEnvelope<Assessment>>(
`/v1/assessments/${encodeURIComponent(assessmentId)}`
);
return response.data;
},
async uploadAssessmentDocument(
assessmentId: string,
file: Blob,
filename: string,
idempotencyKey: string
) {
const form = new FormData();
form.set('file', file, filename);
const response = await request<SingleEnvelope<Document>>(
`/v1/assessments/${encodeURIComponent(assessmentId)}/documents`,
{
method: 'POST',
headers: { 'idempotency-key': idempotencyKey },
body: form
}
);
return response.data;
},
async getDecision(decisionId: string) {
const response = await request<SingleEnvelope<Decision>>(
`/v1/decisions/${encodeURIComponent(decisionId)}`
);
return response.data;
}
};
};

Do not set a multipart Content-Type header when you send FormData. Your runtime adds the required boundary.

Use the client from your server code:

import { createDocktClient } from './dockt';
const dockt = createDocktClient(process.env.DOCKT_API_TOKEN!);
const assessment = await dockt.createAssessment(
{
external_id: 'worker-case-1042',
inputs: [
{ code: 'person.name.first', value: 'Amina', source: { kind: 'integration', reference: 'your_system:worker:1042' } },
{ code: 'person.name.last', value: 'Diallo', source: { kind: 'integration', reference: 'your_system:worker:1042' } },
{ code: 'person.date_of_birth', value: '1990-05-17', source: { kind: 'integration', reference: 'your_system:worker:1042' } },
{ code: 'person.nationality', value: ['FR', 'MA'], source: { kind: 'integration', reference: 'your_system:worker:1042' } },
{ code: 'employment.relationship', value: 'employee', source: { kind: 'integration', reference: 'your_system:assignment:1042' } },
{ code: 'employment.posting_status', value: 'posted', source: { kind: 'integration', reference: 'your_system:assignment:1042' } }
]
},
'assessment-worker-case-1042'
);
console.log(assessment.id, assessment.input_requests, assessment.requirements);

Store assessment.id and the idempotency key in your database before reporting success to the caller of your backend.

If input_requests contains entries, Dockt still needs those details for a check. Send values your system already knows through inputs, with their sources. Dockt continues any checks that have enough information.

Let users upload documents and see the result, including missing or incorrect evidence. Don’t ask them to complete a questionnaire. Complete an assessment shows how to send known values. Assessment inputs lists the field codes and value types.

Read the file in your backend and upload it to the Assessment. This example uses a Blob, so it also works in server runtimes that don’t expose a filesystem:

const document = await dockt.uploadAssessmentDocument(
assessment.id,
new Blob([documentBytes], { type: 'application/pdf' }),
'passport.pdf',
'assessment-worker-case-1042-passport'
);
console.log(document.id, document.status);

documentBytes is the file content your backend received from your application’s private upload or storage layer. Store document.id with that upload record.

The upload response normally has status: "uploaded" or status: "processing". Wait for a notification event or read the Document or Assessment again to check whether processing has finished.

After assessment.completed, fetch the Assessment and its referenced Decision:

const current = await dockt.getAssessment(assessment.id);
if (current.input_requests.length > 0) {
console.log('More context is required', current.input_requests);
}
if (!current.latest_decision) {
console.log('Assessment processing is not complete');
} else {
const decision = await dockt.getDecision(current.latest_decision.decision_id);
console.log(decision.decision, decision.findings, decision.requirements);
}

Store the Decision ID and assessment_input_version your application acts on. Before a delayed or high-impact action, fetch the Assessment again and confirm that its latest_decision.decision_id still matches.

Add these controls in your application:

  • Set connection and response timeouts.
  • Retry only failures that can succeed later.
  • Reuse the same idempotency key and body when retrying a create or upload.
  • Configure a Notification Destination and deduplicate its events.
  • Read unresolved resources again through the API to get their current state.
  • Log x-request-id, but never log credentials or document contents.

Continue with Notification destinations and Test your integration.