POST /api/print/invoice
Endpoint:
POST /api/print/invoice
Auth Scope: Profile Protected (verify_operational_profile_access)
Target Service: Local DaemonX Bridge Daemon (127.0.0.1:9123)
Introduced In: v1.0.0
Last Updated: v1.0.0
Rendering Engine: Headless Microsoft Edge / Google Chrome (300 DPI)
1. Description & Purpose
POST /api/print/invoice enables web applications to print rich, fully styled HTML documents directly to any physical Windows printer (inkjet, laser, or high-resolution continuous thermal rolls) without displaying the browser print dialog (Ctrl+P).
How It Works Under the Hood:
- HTML Ingestion: Accepts a complete HTML string with embedded CSS (fonts, Flexbox/Grid, SVG logos, barcodes, tables).
- Sandbox Watermark Injection: If the counter is running in a Sandbox environment, DaemonX injects top/bottom security banners and a 45° diagonal watermark before rendering.
- Headless Vector Rasterization: Microsoft Edge or Google Chrome renders the HTML headlessly into an exact vector PDF at 300 DPI.
- Direct Spooler Dispatch: The generated vector document is dispatched directly to the target Windows printer queue via
System.Drawing.Printing.PrintDocument. - Instant Cleanup: All temporary PDF and image artifacts are immediately unlinked from
%TEMP%.
2. Authentication & Required Headers
| Header Name | Type | Required | Description | Example |
|---|---|---|---|---|
Content-Type | string | Yes | application/json | application/json |
Origin | string | Yes | Web POS browser origin. Must be whitelisted in profile. | https://pos.yourdomain.com |
X-Bridge-Counter-Id | string (UUID) | Yes | Target counter UUID registered on this workstation. | d402ddec-ecf7-4b39-b57a-86ce6008df05 |
X-Bridge-Profile-Secret | string | Yes | Counter secret issued during pairing (dxp_...). | dxp_202b541b2a72ecc32867e0f62b26b... |
3. TypeScript Contracts
export interface InvoicePrintRequest {
/** Target Windows printer name (from GET /api/printers) */
printer_name: string;
/** Full standalone HTML document string with <style> */
html: string;
/** Target paper format: 'A4' | 'Letter' | 'receipt_80mm'. Default: 'A4' */
format?: 'A4' | 'Letter' | 'receipt_80mm' | string;
/** Number of physical copies to print (1 to 10). Default: 1 */
copies?: number;
/** Document title displayed in Windows Print Queue. Default: 'Nyxzie POS Receipt' */
title?: string;
}
export interface InvoicePrintResponse {
success: boolean;
counter_id: string;
printer: string;
format: string;
pages: number;
copies: number;
}
4. Parameter Matrix
| Parameter | Type | Required | Default | Validation & Description |
|---|---|---|---|---|
printer_name | string | Yes | - | Name of target Windows printer as reported by GET /api/printers. |
html | string | Yes | - | Valid HTML markup. Should include self-contained CSS styles. |
format | string | No | "A4" | Document paper sizing: "A4", "Letter", or custom width. |
copies | integer | No | 1 | Range: 1 to 10. Each copy decrements 1 offline allowance unit when disconnected. |
title | string | No | "POS Receipt" | Job title visible in Windows Spooler queue. |
5. Real-World Request & Response Examples
Example A: Full A4 Invoice Print
Endpoint: POST http://127.0.0.1:9123/api/print/invoice
{
"printer_name": "EPSON L130 Series",
"format": "A4",
"copies": 1,
"title": "Tax Invoice #INV-8891",
"html": "<!DOCTYPE html><html><head><meta charset='utf-8'><style>body { font-family: -apple-system, sans-serif; margin: 20px; color: #111; } .header { border-bottom: 2px solid #7c3aed; padding-bottom: 12px; } .title { font-size: 24px; font-weight: 900; color: #7c3aed; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { padding: 10px; border-bottom: 1px solid #e5e7eb; text-align: left; } th { background: #f9fafb; font-size: 12px; text-transform: uppercase; } .total-row { font-weight: bold; font-size: 16px; }</style></head><body><div class='header'><div class='title'>STUDIO MILAN</div><div>Commercial Tax Invoice #INV-8891</div></div><table><thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Total</th></tr></thead><tbody><tr><td>Italian Linen Blazer (Navy - 40R)</td><td>1</td><td>LKR 28,500.00</td><td>LKR 28,500.00</td></tr><tr><td>Custom Tailoring & Alteration</td><td>1</td><td>LKR 3,500.00</td><td>LKR 3,500.00</td></tr><tr class='total-row'><td colspan='3'>GRAND TOTAL</td><td>LKR 32,000.00</td></tr></tbody></table></body></html>"
}
Successful Response (200 OK)
{
"success": true,
"counter_id": "d402ddec-ecf7-4b39-b57a-86ce6008df05",
"printer": "EPSON L130 Series",
"format": "A4",
"pages": 1,
"copies": 1
}
Example B: Offline Allowance Lockout (403 Forbidden)
{
"detail": {
"error": "DAEMONX_OFFLINE_ALLOWANCE_EXHAUSTED",
"message": "Emergency offline allowance exhausted. Reconnect this counter to continue.",
"counter_id": "d402ddec-ecf7-4b39-b57a-86ce6008df05",
"offline_remaining": 0,
"reconnect_required": true,
"gate_reason": "OFFLINE_ALLOWANCE_EXHAUSTED",
"operation": "print_invoice"
}
}
6. HTML Rendering Best Practices for Silent Spooling
To ensure pixel-perfect printing across all printer brands:
- Use Self-Contained Styles:
Do not rely on external CSS stylesheets (
<link rel="stylesheet">) that require internet requests during rendering. Inline your CSS rules in a<style>block. - Explicit Page Dimensions:
For A4 documents, set
@page { size: A4; margin: 10mm; }in CSS. - Use Web-Safe Fonts or Embedded SVGs:
Standard system fonts (Arial, Segoe UI, Roboto, sans-serif) render instantly without network latency. For logos and barcodes, embed SVG code or inline Base64 data URLs (
data:image/png;base64,...).
7. Sandbox Watermarking
When connected to a Sandbox API Key (nyx_daemonx_sandbox_*), DaemonX automatically injects:
- Red Top Banner:
[ DAEMONX SANDBOX TEST INVOICE - NOT A VALID TAX RECEIPT ] - Red Bottom Banner:
[ TEST RECEIPT ONLY - UNAUTHORIZED FOR COMMERCIAL SALE ] - Center Diagonal Watermark: A semi-transparent 45-degree rotated box with
"DAEMONX SANDBOX - TEST RECEIPT ONLY".
In live environments, zero watermarks are injected.
8. Integration Snippets
TypeScript Client Function
export async function printInvoiceHtml(
request: InvoicePrintRequest,
counterId: string,
profileSecret: string
): Promise<InvoicePrintResponse> {
const res = await fetch('http://127.0.0.1:9123/api/print/invoice', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Bridge-Counter-Id': counterId,
'X-Bridge-Profile-Secret': profileSecret,
},
body: JSON.stringify({
format: 'A4',
copies: 1,
title: 'POS Receipt',
...request,
}),
});
if (!res.ok) {
const errorPayload = await res.json().catch(() => null);
const detail = errorPayload?.detail;
if (res.status === 403 && detail?.reconnect_required) {
throw new Error(`OFFLINE_LOCKED: ${detail.message}`);
}
throw new Error(detail?.message || `Invoice print failed with HTTP ${res.status}`);
}
return (await res.json()) as InvoicePrintResponse;
}