Print Invoice

Print invoice HTML through the local bridge for A4, Letter, or receipt formats.

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:

  1. HTML Ingestion: Accepts a complete HTML string with embedded CSS (fonts, Flexbox/Grid, SVG logos, barcodes, tables).
  2. 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.
  3. Headless Vector Rasterization: Microsoft Edge or Google Chrome renders the HTML headlessly into an exact vector PDF at 300 DPI.
  4. Direct Spooler Dispatch: The generated vector document is dispatched directly to the target Windows printer queue via System.Drawing.Printing.PrintDocument.
  5. Instant Cleanup: All temporary PDF and image artifacts are immediately unlinked from %TEMP%.

2. Authentication & Required Headers

Header NameTypeRequiredDescriptionExample
Content-TypestringYesapplication/jsonapplication/json
OriginstringYesWeb POS browser origin. Must be whitelisted in profile.https://pos.yourdomain.com
X-Bridge-Counter-Idstring (UUID)YesTarget counter UUID registered on this workstation.d402ddec-ecf7-4b39-b57a-86ce6008df05
X-Bridge-Profile-SecretstringYesCounter 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

ParameterTypeRequiredDefaultValidation & Description
printer_namestringYes-Name of target Windows printer as reported by GET /api/printers.
htmlstringYes-Valid HTML markup. Should include self-contained CSS styles.
formatstringNo"A4"Document paper sizing: "A4", "Letter", or custom width.
copiesintegerNo1Range: 1 to 10. Each copy decrements 1 offline allowance unit when disconnected.
titlestringNo"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:

  1. 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.
  2. Explicit Page Dimensions: For A4 documents, set @page { size: A4; margin: 10mm; } in CSS.
  3. 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;
}