KERNIT Documentation

API version2026-05-12Version policy

Node SDK-style client

Use this SDK-style Node client when you want application code to call scan, resolve, and apply as stable methods instead of repeating multipart request code in every workflow.

Client Shape#

This is not a published npm package yet. It is the official docs-side client shape KERNIT will keep aligned with the OpenAPI contract until a packaged SDK is released.

import { readFile, writeFile } from 'node:fs/promises';
import { basename } from 'node:path';

export class KernitHyperlinker {
  constructor({ apiKey, baseUrl = 'https://api.kernit.org' }) {
    if (!apiKey) throw new Error('apiKey is required');
    this.apiKey = apiKey;
    this.baseUrl = baseUrl.replace(/\/$/, '');
  }

  async multipart(endpoint, fields, filePath) {
    const form = new FormData();
    const file = new Blob([await readFile(filePath)], {
      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    });
    form.set('file', file, basename(filePath));
    for (const [key, value] of Object.entries(fields)) {
      if (value === undefined || value === null) continue;
      form.set(key, typeof value === 'string' ? value : JSON.stringify(value));
    }
    const response = await fetch(this.baseUrl + endpoint, {
      method: 'POST',
      headers: { Authorization: 'Bearer ' + this.apiKey },
      body: form
    });
    const text = await response.text();
    if (!response.ok) throw new Error(endpoint + ' failed: ' + response.status + ' ' + text);
    return JSON.parse(text);
  }

  scan(filePath, settings) {
    return this.multipart('/hyperlink-scan', { settings }, filePath);
  }

  resolve(filePath, { settings, scanFingerprint }) {
    return this.multipart('/hyperlink-crossref', { settings, scanFingerprint }, filePath);
  }

  apply(filePath, { settings, scanFingerprint, scanToken, decisions, resolvedWorks = {} }) {
    return this.multipart('/hyperlink-apply', {
      settings,
      scanFingerprint,
      scanToken,
      decisions,
      resolvedWorks
    }, filePath);
  }
}

const kernit = new KernitHyperlinker({ apiKey: process.env.KERNIT_API_KEY });
const settings = {
  "refs": true,
  "figures": "number",
  "tables": "number",
  "equations": "number",
  "sections": "number",
  "doi": true,
  "crossref": true,
  "refTitleLink": false,
  "linkColor": "#0077BD",
  "xrefLinkColor": "#0077BD"
};
const scan = await kernit.scan('paper.docx', settings);
const resolved = await kernit.resolve('paper.docx', { settings, scanFingerprint: scan.scanFingerprint });
const decisions = scan.matches.map((match) => ({
  refId: match.refId,
  status: match.confidence >= 0.9 ? 'approved' : 'skipped',
  targetId: match.targetId
}));
const applied = await kernit.apply('paper.docx', {
  settings,
  scanFingerprint: scan.scanFingerprint,
  scanToken: scan.scanToken,
  resolvedWorks: resolved.resolvedWorks || {},
  decisions
});
await writeFile('paper.linked.docx', Buffer.from(applied.docx, 'base64'));

Method Contract#

MethodEndpointPurpose
scan(filePath, settings)/hyperlink-scanCreate review rows and scan state.
resolve(filePath, state)/hyperlink-crossrefResolve bibliography evidence.
apply(filePath, state)/hyperlink-applyWrite approved links into the DOCX.
Was this page useful?Send a lightweight docs feedback event.
Last updated: May 12, 2026Canonical: https://kernit.org/docs/api/sdk/node/