API overview
Every browser SDK method: connecting and authorising, printers, printing, preview, scanning and jobs — with signatures, parameters, return values and examples.
Last updated
This is the complete list of interfaces available to a web page. All methods are
promise-based and throw structured errors (code / message / retryable) —
see error codes.
This is all a web page can do
Desktop-only privileged capabilities (writing settings, the job content viewer, service migration transactions…) are not a web API and can never be called from a page. A page has exactly what is listed here.
Endpoints and creation
| Item | Value |
|---|---|
| Default endpoint | ws://127.0.0.1:17888/ws |
| Protocol | printlink.v1 (the wire field v is always 1) |
| Browser SDK | http://127.0.0.1:17888/sdk/printlink.js (global PrintLink) |
| npm package | @printlink/sdk |
| Health check | GET /healthz |
| HTTP interface | POST /rpc (same port, see HTTP interface) |
| Scan page download | GET /api/v1/scans/{scanId}/pages/{index} |
import { PrintLinkClient } from '@printlink/sdk';
const client = new PrintLinkClient({
appName: 'My business app', // shown in the pairing prompt and site list
channel: 'erp', // optional: distinguish apps on one machine
endpoint: 'ws://127.0.0.1:17888/ws',// optional, this is the default
requestTimeoutMs: 30_000, // optional per-request timeout
});Connecting and authorising
detect() → connect() → ensureAuthorized() → calls … → close()| Method | Returns | Notes |
|---|---|---|
PrintLinkClient.detect(options?) | DetectResult | Static, no instance needed: installed / reachable / version / reason |
connect() | HelloResult | Connects: agentVersion / protocolVersion / platform / features |
ensureAuthorized(permissions?) | AuthStatusResult | Returns if authorised, otherwise pairs. Also accepts { requestedPermissions, waitForDecision, timeoutMs, signal } |
authStatus() | AuthStatusResult | Current authorisation state and granted permissions |
pair(permissions?) | AuthPairResult | Explicitly start pairing (opens the local prompt) |
revoke() | void | Revoke this site's own token |
onConnectionStateChange(listener) | unsubscribe | Transport / authorisation / ready snapshot |
onAuthDecisionChanged(handler) | unsubscribe | The user accepted or refused pairing |
onServiceMigrated(handler) | unsubscribe | The service port changed |
close() | void | Disconnect and clear subscriptions — always call this |
ensureAuthorized({ waitForDecision: true }) waits for the user's decision
instead of failing immediately with PAIRING_PENDING, which suits a
"click print, then wait for approval" interaction.
features is a capability list (e.g. scanner.v1) — use it for feature
detection rather than comparing version numbers.
Printers and profiles
| Method | Returns | Notes |
|---|---|---|
listPrinters() | { devices, queues } | Queues with live status, plus physical device grouping |
defaultPrinter() | string | null | The OS default printer's queueId |
getCapabilities(queueId, refresh?) | PrinterCapabilities | Paper, duplex, colour, copies, trays, media, resolutions |
printerStatus(queueId) | PrinterStatusSnapshot | Immediate status |
onPrinterStatusChanged(handler) | unsubscribe | Status change events |
setPreferredPrinter(queueId | null) | PrinterListResult | Set or clear the preferred printer |
openPrinterSettings(queueId) | { opened } | Open the OS printer settings |
listProfiles(queueId?) | profile summaries | List profiles |
getProfile(id) | profile summary | One profile |
createProfileFromNative(queueId, name) | profile summary | Capture the printer's current native config |
renameProfile(id, name) | profile summary | Rename |
setDefaultProfile(id) | profile summary | Make it the printer's default |
setProfileStandard(id, options) | profile summary | Write cross-platform standard options |
deleteProfile(id) | void | Delete |
Details in printers & profiles.
Uploading and printing
| Method | Returns | Notes |
|---|---|---|
uploadAsset(bytes, mime) | AssetRef | Upload a PDF or image; chunked with SHA-256 verification |
validate(params) | JobValidateResult | Pre-flight: requested → effective + warnings, no side effects |
compose({ queueId }) | PrintJobBuilder | The chained builder, below |
print(params) | JobPrintResult | Silent print; returns a jobId immediately |
printAndWait(params, options?) | JobStatusEventData | Submit and wait for the terminal state; options.onStatus receives intermediate states, timeoutMs defaults to 120 s |
JobPrintParams
interface JobPrintParams {
queueId: string;
source: PrintSource; // { items: SourceItem[] }, 1..=50
options?: PrintOptions; // see the print options page
profileId?: string; // omitted = printer default; '' = explicitly none
profileMode?: 'default' | 'explicit' | 'none';
title?: string; // shown in the console job list
idempotencyKey?: string; // 1..128 visible ASCII; a repeat runs once
channel?: string; // ^[a-z][a-z0-9_-]*$, up to 64 characters
}PrintSource / SourceItem
type SourceItem =
| { type: 'image'; asset?: AssetRef; remote?: { url: string }; pageLayout?: PageLayout }
| { type: 'pdf'; asset: AssetRef; pageRange?: string }
| { type: 'html'; asset?: AssetRef; remote?: { url: string }; pageRange?: string }
| { type: 'document'; document: PrintDocument; data?: unknown };asset and remote are mutually exclusive (both or neither is
INVALID_REQUEST). remote accepts public addresses only — see
content sources.
PrintJobBuilder (what compose() returns)
| Method | Notes |
|---|---|
.paper('auto' | name | PageSize) / .pageSize(w, h, unit?) | The job's paper, set once |
.copies(n) .orientation(v) .duplex(v) .color(bool) .borderless(bool) .quality(v) .mediaType(v) .tray(v) .collate(bool) .reverseOrder(bool) | Correspond to options.* |
.pageLayout('auto' | 'actual' | 'fill') | Job-wide preset; no custom |
.margins(v) .outputPageRange(v) .options(patch) | Margins, output page range, bulk patch |
.profile(id) .compatibility(mode) | Reference a profile; compatibility mode |
.title(t) .idempotencyKey(k) | Title and idempotency key |
.addPdf(src) → .pageRange(r) | One PDF |
.addImage(src) → .imageLayout(layout) | One image, with its own layout |
.addHtml(src) → .pageRange(r) | One web page |
.addDocument(doc) → .data(d) | One template with its data |
.add(item) | A ready-made wire item (e.g. a Hiprint conversion) |
.validate() .preview() .print() .printAndWait() .toParams() | Submit |
The types reject invalid combinations: .addImage(x).pageRange(),
.addPdf(x).imageLayout() and a job-level .pageLayout({ mode: 'custom' }) are
all compile errors.
Preview
| Method | Returns | Notes |
|---|---|---|
preview(params) | PreviewOpenResult | Opens the preview window; same parameters as print() |
previewUpdate({ previewSessionId, ... }) | PreviewOpenResult | Update the preview |
previewGetPage(sessionId, pageIndex) | PreviewGetPageResult | Rasterise one page (trusted local UI only) |
previewPrint(sessionId) | JobPrintResult | Print the same artefact shown |
previewClose(sessionId) | void | Close the session |
interface PreviewOpenResult {
previewSessionId: string;
pageCount: number;
artifactSha256: string;
warnings: PrintWarning[];
windowShown: boolean;
source: SourceSummary; // which output pages each item covers
}
interface PreviewUpdateParams {
previewSessionId: string;
source?: PrintSource; // full replacement
options?: PrintOptions; // full replacement
pageLayout?: PreviewPageLayoutUpdate; // targeted update
queueId?: string;
profileId?: string;
profileMode?: 'default' | 'explicit' | 'none';
}
type PreviewPageLayoutUpdate =
| { scope: 'all'; layout: PageLayoutPreset }
| { scope: 'image'; itemIndex: number; layout: PageLayout };Details in preview.
Jobs
| Method | Returns | Notes |
|---|---|---|
getJob(jobId) | PrintJob | Details (only jobs from this site) |
listJobs(limit?) | PrintJob[] | Job list |
cancelJob(jobId) | PrintJob | Cancel a job |
onJobStatus(handler) | unsubscribe | Job status transitions |
onDuplicateSuppressed(handler) | unsubscribe | An idempotency key suppressed a repeat |
getDiagnostics() | diagnostics summary | Sanitised system information |
Scanning
scanner.read and scan.run are not granted by default.
| Method | Notes |
|---|---|
scannerList(refresh?) | List scanners |
scannerGet(scannerId) | One scanner |
scannerCapabilities(scannerId, refresh?) | Source × resolution × colour × format × size |
scannerStatus(scannerId) | Immediate status |
scanValidate(scannerId, options, compatibility?) | Side-effect-free validation |
scanStart(params) | Create the job (may enter awaiting-consent) |
scan(params, options?) | Start and wait for the terminal state |
scanStatus(scanId) / scanList(limit?) | Query |
scanCancel(scanId) | Cancel |
scanGetPage(scanId, index, maxWidthPx?, pdfPage?) | A single small page |
fetchScanPage(scanId, index, ticket?) | Fetch the page as a Blob |
onScanStatus(handler) / onScanPageReady(handler) / onScannerListChanged(handler) | Events |
Details in scan.
Data models
type PageLayoutPreset =
| { mode: 'auto' } // scale to fit the printable area, centred, no cropping
| { mode: 'actual' } // 1:1, centred, cropped where it overflows
| { mode: 'fill' }; // scale up to cover, cropping the overflow
type PageLayout =
| PageLayoutPreset
| {
mode: 'custom';
horizontal?: 'left' | 'center' | 'right';
vertical?: 'top' | 'center' | 'bottom';
size?: { widthMm?: number; heightMm?: number }; // exclusive with scalePercent
scalePercent?: number; // (0, 1000]
offset?: { xMm?: number; yMm?: number };
rotate?: 0 | 90 | 180 | 270;
flipHorizontal?: boolean;
flipVertical?: boolean;
};
interface AssetRef { id: string; sha256: string; mime: string; size: number }
interface PreviewGetPageResult {
pageIndex: number;
widthPx: number;
heightPx: number;
pngBase64: string;
origin: { itemIndex: number; kind: string; itemPageIndex: number };
pageLayout: PageLayout; // the layout actually used, always present
layout?: PageLayoutGeometry; // millimetre geometry
}Capability resolution is mandatory
Before rendering, every job goes through capability resolution: requested values
are resolved against the printer's real capabilities into effective values, and
anything unsatisfiable is downgraded with structured warnings. validate()
gives you the same result before submitting.