Api Endpoint

Copy from your ZeroPrint client

Print Request

POST /api/print
Content-Type: application/json

Request Parameters

FieldTypeRequiredDescription
targetstringYesTarget printer ID, can be copied from the client
datastringYesPrint job data. Plaintext JSON (debug only) or RSA+AES-256-GCM encrypted then Base64 encoded (recommended for production)

Request Example

Plaintext Mode (debug only)

{
  "target": "<printer ID>",
  "data": "{\"url\":\"https://example.com/document.pdf\",\"copies\":1,\"id\":\"order_123\",\"callbackUrl\":\"https://your-server.com/callback\"}"
}

Encrypted Mode (recommended for production)

{
  "target": "<printer ID>",
  "data": "SGVsbG8gV29ybGQgZm9yIGVuY3J5cHRlZC9pbnRlcmFjdGlvbiBvbmx5..."
}

Data Field Parameters

pageSize, duplex, color, orientation, resolution — Copy from client for printer-supported values. Uses printer defaults if not provided.

FieldTypeRequiredDescription
urlstringYesURL of the file to print, supports public and internal network addresses
copiesnumberNoNumber of copies, default 1
idstringNoTask ID, for callback correlation
callbackUrlstringNoPrint result callback URL
pageSizestringNoPage size (copy from client)
duplexstringNoDuplex mode (copy from client)
colorstringNoColor mode (copy from client)
orientationstringNoPage orientation (copy from client)
resolutionstringNoPrint resolution (copy from client)

Response

Success: HTTP 200 OK, no response body.

Bad Request: HTTP 400 Bad Request

Server Error: HTTP 500 Internal Server Error

{
  "code": "INVALID_DATA",
  "message": "data is required and must be a non-empty string"
}
codemessage
INVALID_TARGETtarget is required and must be a 64-character lowercase hex string (a-f, 0-9)
INVALID_DATAdata is required and must be a non-empty string
INTERNAL_ERRORinternal server error

Callback

After the print job completes, the client sends a POST request to callbackUrl to notify the result. Both id and callbackUrl must be provided to trigger the callback.

POST {callbackUrl}
Content-Type: application/json

Callback Parameters

FieldTypeDescription
idstringTask ID (matches the id in request)
successbooleanWhether printing succeeded

Success Callback

{ "id": "order_123", "success": true }

Failure Callback

{ "id": "order_123", "success": false }

Callback timeout: 5 seconds. HTTP status 2xx is considered success. Callback is fired regardless of print success or failure.

Encryption

RSA-2048 + AES-256-GCM hybrid encryption is recommended for production. Private key is stored locally on the client only; the cloud cannot decrypt.

Encryption Steps

  1. Copy the public key (from client)
  2. Generate AES-256 key and 12-byte Nonce
  3. Encrypt JSON with AES-256-GCM (with auth tag)
  4. Encrypt AES key with RSA-OAEP(SHA256) (256 bytes)
  5. Concatenate: encrypted key + Nonce + ciphertext + tag
  6. Base64 encode as the data value

Data Structure

[RSA-encrypted AES key (256 bytes)][GCM Nonce (12 bytes)][Ciphertext + auth tag]

Code Examples

const crypto = require("crypto");

// RSA+AES-256-GCM hybrid encryption: encrypt plaintext with the public key, return Base64 ciphertext
function encryptData(publicKey, plaintext) {
    const wrapped = publicKey.match(/.{1,64}/g).join("\n");
    const pemKey = `-----BEGIN PUBLIC KEY-----\n${wrapped}\n-----END PUBLIC KEY-----`;
    const aesKey = crypto.randomBytes(32);
    const nonce = crypto.randomBytes(12);
    const cipher = crypto.createCipheriv("aes-256-gcm", aesKey, nonce);
    const ciphertext = Buffer.concat([
        cipher.update(plaintext, "utf8"),
        cipher.final(),
    ]);
    const tag = cipher.getAuthTag();
    const encryptedAesKey = crypto.publicEncrypt(
        {
            key: pemKey,
            padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
            oaepHash: "sha256",
        },
        aesKey,
    );
    return Buffer.concat([encryptedAesKey, nonce, ciphertext, tag]).toString("base64");
}

// Send a print request (plaintext mode when publicKey is empty)
async function sendPrintRequest(target, printData, publicKey) {
    const plaintext = JSON.stringify(printData);
    const data = publicKey ? encryptData(publicKey, plaintext) : plaintext;
    const response = await fetch("https://<Api Endpoint>/api/print", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ target, data }),
    });
    if (!response.ok) throw await response.json();
    return { status: "success" };
}

// ── Build request data ──
const target = "<printer ID>";
const publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAO...";
const printData = {
    url: "https://example.com/document.pdf",
    copies: 1,
    id: "order_123",
    callbackUrl: "https://your-server.com/callback",
};

// ── Encrypted mode: recommended for production ──
sendPrintRequest(target, printData, publicKey)
    .then(() => console.log("Encrypted mode - request successful"))
    .catch((error) => console.error("Request failed:", error));

// ── Plaintext mode: debug only ──
sendPrintRequest(target, printData)
    .then(() => console.log("Plaintext mode - request successful"))
    .catch((error) => console.error("Request failed:", error));
// RSA+AES-256-GCM hybrid encryption (browser version)
async function encryptData(publicKey, plaintext) {
    const publicKeyBytes = Uint8Array.from(atob(publicKey), c => c.charCodeAt(0));
    const publicKeyObj = await crypto.subtle.importKey(
        "spki", publicKeyBytes,
        { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"]
    );
    const aesKey = await crypto.subtle.generateKey(
        { name: "AES-GCM", length: 256 }, true, ["encrypt"]
    );
    const nonce = crypto.getRandomValues(new Uint8Array(12));
    const data = new TextEncoder().encode(plaintext);
    const ciphertext = new Uint8Array(
        await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, aesKey, data)
    );
    const aesKeyBytes = new Uint8Array(await crypto.subtle.exportKey("raw", aesKey));
    const encryptedAesKey = new Uint8Array(
        await crypto.subtle.encrypt(
            { name: "RSA-OAEP", hash: "SHA-256" }, publicKeyObj, aesKeyBytes
        )
    );
    const combined = new Uint8Array(encryptedAesKey.length + nonce.length + ciphertext.length);
    combined.set(encryptedAesKey, 0);
    combined.set(nonce, encryptedAesKey.length);
    combined.set(ciphertext, encryptedAesKey.length + nonce.length);
    return btoa(String.fromCharCode(...combined));
}

// Send a print request (browser version, plaintext mode when publicKey is empty)
async function sendPrintRequest(target, printData, publicKey) {
    const plaintext = JSON.stringify(printData);
    const data = publicKey ? await encryptData(publicKey, plaintext) : plaintext;
    const response = await fetch("https://<Api Endpoint>/api/print", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ target, data }),
    });
    if (!response.ok) throw await response.json();
    return { status: "success" };
}

// ── Build request data ──
const target = "<printer ID>";
const publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAO...";
const printData = {
    url: "https://example.com/document.pdf",
    copies: 1,
    id: "order_123",
    callbackUrl: "https://your-server.com/callback",
};

// ── Encrypted mode: recommended for production ──
sendPrintRequest(target, printData, publicKey)
    .then(() => console.log("Encrypted mode - request successful"))
    .catch((error) => console.error("Request failed:", error));

// ── Plaintext mode: debug only ──
sendPrintRequest(target, printData)
    .then(() => console.log("Plaintext mode - request successful"))
    .catch((error) => console.error("Request failed:", error));

For other languages, follow the same logic or use AI-assisted translation.