Skip to content

Call Dockt from TypeScript

This guide shows how to call Dockt from a TypeScript backend using the public OpenAPI contract and a workspace credential.

The example uses native fetch. It creates an Assessment, uploads evidence, and reads the resulting 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',
worker: {
first_name: 'Amina',
last_name: 'Diallo',
date_of_birth: '1990-05-17',
nationality: 'FR'
},
context: [
{ code: 'employment.relationship', value: 'posted_employee' },
{ code: 'employment.employer_country', value: 'FR' }
]
},
'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, collect those context values and update the Assessment before requesting evidence. The Assessment inputs reference explains each value type and code.

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 webhook or poll the canonical resource before reading a result.

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);
} else 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.
  • Verify and deduplicate signed webhooks.
  • Reconcile unresolved resources with canonical API reads.
  • Log x-request-id, but never log credentials or document contents.

Continue with Receive webhooks and Test your integration.