KERNIT Documentation

POST/hyperlink-apply
API version2026-05-12Version policy

POST /hyperlink-apply

/hyperlink-apply writes the approved links into the DOCX. It verifies that the file, settings, scan token, and review graph still match before returning final output.

POST /hyperlink-apply

Writes approved citation, cross-reference, DOI, URL, and resolver decisions into the same DOCX used during scan. The route verifies scanToken, scanFingerprint, file hash, settings hash, persisted metadata hash, caller, and graph state before returning final output.

AuthBearer API key BillingConsumes apply or document-processing allowance after scan-token validation. Hosthttps://api.kernit.org

Contract Source#

This reference is backed by /docs/openapi.json. The source schema lives in app/docs/openapi.json, so request fields, response schemas, examples, and validation stay tied to one API contract.

Request Fields#

Defined by the OpenAPI contract requestBody multipart/form-data.

FieldTypeRequiredDescription
filestring:binaryYesSame DOCX package used during scan.
settingsstringYesJSON string matching the settings used during scan.
scanTokenstringYesSigned token returned by scan or resolver.
scanFingerprintstringYesFingerprint returned by scan or resolver.
decisionsarray<ReviewDecision>YesJSON array of ReviewDecision objects.
resolvedWorksstringNoOptional JSON resolver evidence to apply when approved.
cslFilestring:binaryNoOptional CSL XML file for controlled bibliography rewrite.
detectedCslIdstringNoOptional detected CSL style id.
applyBibRewritetrue | falseNoSet true only when bibliography rewrite is explicitly approved.

Example Request#

curl -X POST https://api.kernit.org/hyperlink-apply \
  -H "Authorization: Bearer sk_kernit_live_YOUR_KEY" \
  -F "file=@paper.docx" \
  -F 'settings={"refs":true,"figures":"number","tables":"number","equations":"number","sections":"number","doi":true}' \
  -F "scanToken=..." \
  -F "scanFingerprint=..." \
  -F 'decisions=[{"refId":"r1","status":"approved"}]' \
  -F 'resolvedWorks={"r1":{"doi":"10.1234/example","confidence":0.94}}' \
  -F "cslFile=@paper.docx" \
  -F "detectedCslId=..." \
  -F "applyBibRewrite=..."

Code Examples#

curl
curl -X POST https://api.kernit.org/hyperlink-apply \
  -H "Authorization: Bearer sk_kernit_live_YOUR_KEY" \
  -F "file=@paper.docx" \
  -F 'settings={"refs":true,"figures":"number","tables":"number","equations":"number","sections":"number","doi":true}' \
  -F "scanToken=..." \
  -F "scanFingerprint=..." \
  -F 'decisions=[{"refId":"r1","status":"approved"}]' \
  -F 'resolvedWorks={"r1":{"doi":"10.1234/example","confidence":0.94}}' \
  -F "cslFile=@paper.docx" \
  -F "detectedCslId=..." \
  -F "applyBibRewrite=..."
JavaScript
const apiKey = 'sk_kernit_live_YOUR_KEY';
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('settings', "{\"refs\":true,\"figures\":\"number\",\"tables\":\"number\",\"equations\":\"number\",\"sections\":\"number\",\"doi\":true,\"crossref\":true}");
form.append('scanToken', "eyJ...");
form.append('scanFingerprint', "sha256:...");
form.append('decisions', "[{\"refId\":\"r1\",\"status\":\"approved\"}]");
form.append('resolvedWorks', "{\"r1\":{\"doi\":\"10.1234/example\",\"confidence\":0.94}}");
form.append('cslFile', fileInput.files[0]);
form.append('detectedCslId', "...");
form.append('applyBibRewrite', "...");

const response = await fetch('https://api.kernit.org/hyperlink-apply', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + apiKey },
  body: form
});

const text = await response.text();
Python
import requests

api_key = 'sk_kernit_live_YOUR_KEY'

with open('paper.docx', 'rb') as docx:
    response = requests.post(
        'https://api.kernit.org/hyperlink-apply',
        headers={'Authorization': f'Bearer {api_key}'},
        files={'file': ('paper.docx', docx, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')},
        data={
        'settings': "{\"refs\":true,\"figures\":\"number\",\"tables\":\"number\",\"equations\":\"number\",\"sections\":\"number\",\"doi\":true,\"crossref\":true}",
        'scanToken': "eyJ...",
        'scanFingerprint': "sha256:...",
        'decisions': "[{\"refId\":\"r1\",\"status\":\"approved\"}]",
        'resolvedWorks': "{\"r1\":{\"doi\":\"10.1234/example\",\"confidence\":0.94}}",
        'detectedCslId': "...",
        'applyBibRewrite': "...",
    },
    timeout=480
    )

print(response.status_code)
print(response.text)

Try This Endpoint#

POST /hyperlink-apply

OpenAPI-backed request builder for this operation.

9 request fields 5 required 6 responses

Request Preview

Fill request fields to preview multipart form data.

Response Output

Response output will appear here.

Responses#

StatusMeaningSchema
200Base64 DOCX and apply statistics.ApplyResult
400Invalid request shape, missing file, invalid JSON, or rejected DOCX.ErrorResponse
401Scan token missing, invalid, or not aligned with file/settings/graph/caller state.ErrorResponse
402No credits or plan allowance available.ErrorResponse
413DOCX exceeds the current 25 MB limit.ErrorResponse
defaultUnexpected KERNIT-side service error.ErrorResponse

Example Success Body#

{
  "docx": "UEsDBBQAAAA...",
  "linkCount": 47,
  "statCounts": {
    "cite": 23,
    "fig": 6,
    "tbl": 8
  },
  "appliedDecisions": 4,
  "unmatched": []
}

Error Examples#

400 Invalid request shape, missing file, invalid JSON, or rejected DOCX.
{
  "error": "Invalid JSON in form data"
}
401 Scan token missing, invalid, or not aligned with file/settings/graph/caller state.
{
  "error": "scan token invalid",
  "reason": "missing"
}
402 No credits or plan allowance available.
{
  "error": "No credits remaining"
}
413 DOCX exceeds the current 25 MB limit.
{
  "error": "File exceeds 25MB limit"
}

Implementation Edge Cases#

CaseExpected handling
File mismatchReturn scan-token validation failure. Apply must receive the same DOCX package used during scan.
Settings mismatchReturn scan-token validation failure. Store settings with the review session and submit them unchanged.
Missing or invalid decisionsReturn 400. Decisions must use approved, skipped, retargeted, or link_only statuses from the ReviewDecision schema.
No apply allowanceReturn 402. Route the user to billing, credits, or team allowance rather than retrying the same request.
Do not regenerate settings between scan and apply. Settings mismatches cause scan-token validation failures.
Was this page useful?Send a lightweight docs feedback event.
Last updated: May 12, 2026Canonical: https://kernit.org/docs/api/apply/