Docs
BlogHomeStart building

Document Scan / OCR (totalum-sdk/scan)


import … from 'totalum-sdk/scan' — or the same namespace on totalum from 'totalum-sdk'. Install, configuration and errors: Totalum SDK.

Read documents and images: extract the fields you describe (an invoice's number, date and total) as JSON with document(), or get the plain text of every page with ocr(). The document can be a project file, a URL or a file name of the project. Billed in credits.

ts
const { data } = await totalum.scan.document({
  key: invoice.key,
  properties: { total: { type: 'number', description: 'the invoice total' } },
});
Method or typeWhat it does
totalumScanCreates the scan namespace (the same object as totalum.scan, scope scan): documents and images read by a vision model.
scan.documentReads a document or image (a PDF, a photo, a scan) and returns the fields you describe — an invoice's number, date and total, an ID card's name — as JSON.
scan.ocrThe text of a document or image (OCR), as Markdown per page, keeping reading order and tables.
ScanDocumentInputThe input of scan.document(): one document and the fields to extract.
ScanDocumentResultWhat scan.document() returns: the extracted fields (one set per page with processEveryPdfPageAsDifferentScan), details of the scan, and what it cost.
ScanOcrInputThe input of scan.ocr(): one document.
ScanOcrOutputThe text of a document, from scan.ocr().

#totalumScan

ts
totalumScan(options?: TotalumClientOptions): TotalumScan

Creates the scan namespace (the same object as totalum.scan, scope scan): documents and images read by a vision model.

Parameters

NameTypeRequiredDescription
optionsTotalumClientOptionsnoThe project key, API URL and environment; each falls back to its environment variable.
options.keystringnoProject key tlm_pk_…; default TOTALUM_PROJECT_KEY. Server-side only.
options.apiUrlstringnoThe Totalum API's URL: default TOTALUM_SDK_API_URL, else https://sdk-api.totalum.app.
options.env'dev' | 'live'noSent as x-totalum-env on every call (the database it targets, and dev vs live usage); default TOTALUM_ENV, else live.

Returns TotalumScan — The scan namespace: the methods below.

Example

ts
import { totalumScan } from 'totalum-sdk/scan';

const scan = totalumScan();
const { text } = await scan.ocr({ key: 'p/acme-crm/01M4P0SFVZXNRS871ZSKZNWHY0.png' });

The namespace's type is exported as TotalumScan (import type { TotalumScan } from 'totalum-sdk/scan').

#scan.document

ts
scan.document(input: ScanDocumentInput): Promise<ScanDocumentResult>

Reads a document or image (a PDF, a photo, a scan) and returns the fields you describe — an invoice's number, date and total, an ID card's name — as JSON. Describe each field with a JSON Schema type and a description; fields not found are null. Pass exactly one of key, fileName or url.

Parameters

NameTypeRequiredDescription
inputScanDocumentInputyesThe document and the fields to extract.
input.propertiesRecord<string, Record<string, unknown>>yesThe fields to extract, as JSON Schema properties: { total: { type: "number", description: "the invoice total" } }. A good description gives better results.
input.options{ model?, removeFileAfterScan?, returnOcrFullResult?, scanDescription?, processEveryPdfPageAsDifferentScan?, maxPages?, pdfPages?, minimumConfidence? }noHow the document is read.
input.options.model'scanum' | 'scanum-pro' | 'scanum-eye' | 'scanum-eye-pro'noscanum / scanum-eye (default: the fast vision model) or scanum-pro / scanum-eye-pro (the smarter model, for hard documents).
input.options.removeFileAfterScanbooleannoAccepted for compatibility; has no effect (delete the file with files.delete).
input.options.returnOcrFullResultbooleannoAccepted for compatibility; has no effect (use scan.ocr for the text).
input.options.scanDescriptionstringnoWhat the document is, in words (a Spanish electricity bill): helps the model.
input.options.processEveryPdfPageAsDifferentScanbooleannotrue extracts the fields once per page (data is then an array): a PDF of many receipts.
input.options.maxPagesnumbernoAccepted for compatibility; has no effect. Allowed: > 0, ≤ 200.
input.options.pdfPagesnumber[]noAccepted for compatibility; has no effect.
input.options.minimumConfidencenumbernoAccepted for compatibility; has no effect. Allowed: ≥ 0, ≤ 1.
input.fileNamestringnoSame as key (the name of the first scan API).
input.keystringnoThe document as a project file key (a PDF or an image).
input.urlstringnoThe document as a URL (a public https:// URL, or a project file URL). Allowed: a URL.

Returns Promise<ScanDocumentResult> — The extracted fields, details of the scan, and what it cost.

FieldTypeAlways presentDescription
dataRecord<string, unknown> | (Record<string, unknown>)[]yesThe fields you described in properties, with the values read from the document (null when absent); an array of them, one per page, with processEveryPdfPageAsDifferentScan.
metadata{ usageUnits, exactUsageUnits, pages, provider, credits }yesDetails of the scan, kept in the shape of the first scan API.
metadata.usageUnitsnumberyesPages read.
metadata.exactUsageUnitsnumberyesSame as usageUnits.
metadata.pagesnumberyesPages in the document.
metadata.providerstringyesAlways 'totalum'.
metadata.creditsnumberyesSame as usage.credits.
usage{ credits }yesWhat the scan cost.
usage.creditsnumberyesCredits charged for this call.

Errors — besides the errors every call can throw:

CodeHTTPWhen
UNSUPPORTED_FILE_TYPE400The file is not a PDF or an image.
FILE_NOT_FOUND404No file with this key.
FILE_KEY_FORBIDDEN403The key belongs to another project.
FILE_TOO_LARGE413The file is over the plan's largest file.
URL_NOT_ALLOWED400The url is not a public http(s) URL.
SCAN_DOCUMENT_ERROR502The document could not be read; retry, or try model: 'scanum-pro'.

Example

ts
const scan = await totalum.scan.document({
  key: invoice.key,
  properties: {
    invoiceNumber: { type: 'string', description: 'the invoice number' },
    issueDate: { type: 'string', description: 'the issue date as YYYY-MM-DD' },
    total: { type: 'number', description: 'the total amount including tax' },
  },
});

Result:

json
{
  "data": { "invoiceNumber": "F-2026-0012", "issueDate": "2026-09-30", "total": 1210 },
  "metadata": { "usageUnits": 1, "exactUsageUnits": 1, "pages": 1, "provider": "totalum", "credits": 0.0039 },
  "usage": { "credits": 0.0039 }
}

#scan.ocr

ts
scan.ocr(input: ScanOcrInput): Promise<{ pages, text, fullDetails?, usage }>

The text of a document or image (OCR), as Markdown per page, keeping reading order and tables. Use it to index a PDF for search, or to read a photo of a sign. Long PDFs are read in parallel chunks. Pass exactly one of key, fileName or url.

Parameters

NameTypeRequiredDescription
inputScanOcrInputyesThe document to read.
input.pagesnumber[]noAccepted for compatibility; has no effect (every page is read).
input.fileNamestringnoSame as key (the name of the first scan API).
input.keystringnoThe document as a project file key (a PDF or an image).
input.urlstringnoThe document as a URL (a public https:// URL, or a project file URL). Allowed: a URL.

Returns Promise<{ pages, text, fullDetails?, usage }> — The whole text, the text of each page, and what it cost.

FieldTypeAlways presentDescription
pages({ markdown, width, height, words? })[]yesOne entry per page.
pages.markdownstringyesThe page's text as Markdown (tables kept).
pages.widthnumberyesNot measured today: always 0.
pages.heightnumberyesNot measured today: always 0.
pages.words({ text, bbox })[]noNot returned today.
pages.words.textstringyesNot returned today.
pages.words.bboxnumber[]yesNot returned today.
textstringyesThe whole text, pages separated by blank lines.
fullDetailsunknownnoNot returned today.
usage{ credits }yesWhat the call cost.
usage.creditsnumberyesCredits charged for this call.

Errors — besides the errors every call can throw:

CodeHTTPWhen
UNSUPPORTED_FILE_TYPE400The file is not a PDF or an image.
FILE_NOT_FOUND404No file with this key.
FILE_KEY_FORBIDDEN403The key belongs to another project.
FILE_TOO_LARGE413The file is over the plan's largest file.
OCR_PDF_PROCESSING_ERROR502A PDF could not be read.
OCR_IMAGE_PROCESSING_ERROR502An image could not be read.

Example

ts
const { text, pages } = await totalum.scan.ocr({ key: 'p/acme-crm/01M4P0SFVZXNRS871ZSKZNWHY0.png' });

Result:

json
{
  "text": "TOTALUM 42",
  "pages": [{ "markdown": "TOTALUM 42", "width": 0, "height": 0 }],
  "usage": { "credits": 0.021 }
}

#ScanDocumentInput

The input of scan.document(): one document and the fields to extract.

NameTypeRequiredDescription
propertiesRecord<string, Record<string, unknown>>yesThe fields to extract, as JSON Schema properties: { total: { type: "number", description: "the invoice total" } }. A good description gives better results.
options{ model?, removeFileAfterScan?, returnOcrFullResult?, scanDescription?, processEveryPdfPageAsDifferentScan?, maxPages?, pdfPages?, minimumConfidence? }noHow the document is read.
options.model'scanum' | 'scanum-pro' | 'scanum-eye' | 'scanum-eye-pro'noscanum / scanum-eye (default: the fast vision model) or scanum-pro / scanum-eye-pro (the smarter model, for hard documents).
options.removeFileAfterScanbooleannoAccepted for compatibility; has no effect (delete the file with files.delete).
options.returnOcrFullResultbooleannoAccepted for compatibility; has no effect (use scan.ocr for the text).
options.scanDescriptionstringnoWhat the document is, in words (a Spanish electricity bill): helps the model.
options.processEveryPdfPageAsDifferentScanbooleannotrue extracts the fields once per page (data is then an array): a PDF of many receipts.
options.maxPagesnumbernoAccepted for compatibility; has no effect. Allowed: > 0, ≤ 200.
options.pdfPagesnumber[]noAccepted for compatibility; has no effect.
options.minimumConfidencenumbernoAccepted for compatibility; has no effect. Allowed: ≥ 0, ≤ 1.
fileNamestringnoSame as key (the name of the first scan API).
keystringnoThe document as a project file key (a PDF or an image).
urlstringnoThe document as a URL (a public https:// URL, or a project file URL). Allowed: a URL.

#ScanDocumentResult

What scan.document() returns: the extracted fields (one set per page with processEveryPdfPageAsDifferentScan), details of the scan, and what it cost.

FieldTypeAlways presentDescription
dataRecord<string, unknown> | (Record<string, unknown>)[]yesThe fields you described in properties, with the values read from the document (null when absent); an array of them, one per page, with processEveryPdfPageAsDifferentScan.
metadata{ usageUnits, exactUsageUnits, pages, provider, credits }yesDetails of the scan, kept in the shape of the first scan API.
metadata.usageUnitsnumberyesPages read.
metadata.exactUsageUnitsnumberyesSame as usageUnits.
metadata.pagesnumberyesPages in the document.
metadata.providerstringyesAlways 'totalum'.
metadata.creditsnumberyesSame as usage.credits.
usage{ credits }yesWhat the scan cost.
usage.creditsnumberyesCredits charged for this call.

#ScanOcrInput

The input of scan.ocr(): one document.

NameTypeRequiredDescription
pagesnumber[]noAccepted for compatibility; has no effect (every page is read).
fileNamestringnoSame as key (the name of the first scan API).
keystringnoThe document as a project file key (a PDF or an image).
urlstringnoThe document as a URL (a public https:// URL, or a project file URL). Allowed: a URL.

#ScanOcrOutput

The text of a document, from scan.ocr().

FieldTypeAlways presentDescription
textstringyesThe whole text, pages separated by blank lines.
pages({ markdown, width, height, words? })[]yesOne entry per page.
pages.markdownstringyesThe page's text as Markdown (tables kept).
pages.widthnumberyesNot measured today: always 0.
pages.heightnumberyesNot measured today: always 0.
pages.words({ text, bbox })[]noNot returned today.
pages.words.textstringyesNot returned today.
pages.words.bboxnumber[]yesNot returned today.
fullDetailsunknownnoNot returned today.