Lenbird Print

API-dokumentation

Lenbird Print låter er hemsida skicka utskrifter direkt till etikettskrivaren på lagret. Flöde: hemsida → print.lenbird.com → lagerdator (Lenbird Print Client) → skrivare. API:et följer PrintNodes fältnamn så att befintliga integrationsmönster kan återanvändas.

Innehåll

Autentisering

Skapa en API-nyckel under API-nycklar i admin. Nyckeln visas bara en gång. Skicka den i varje anrop på något av följande sätt:

Authorization: Bearer lbp_live_xxxxxxxxxxxxxxxx
# eller (PrintNode-stil) HTTP Basic med nyckeln som användarnamn och tomt lösenord
Authorization: Basic base64("lbp_live_xxxxxxxxxxxxxxxx:")
# eller
X-Api-Key: lbp_live_xxxxxxxxxxxxxxxx

Bas-URL: https://print.lenbird.com/api/v1. Alla svar är JSON (utom /ping).

GET /api/v1/ping
– svarar OK utan autentisering.
GET /api/v1/whoami
– verifierar nyckeln och returnerar kontot.

Datorer & skrivare

GET /api/v1/computers
GET /api/v1/printers
GET /api/v1/printers/{id}
GET /api/v1/computers/{id}/printers

Skrivare rapporteras automatiskt av klienten. Använd skrivarens id när ni skapar jobb (id:t är stabilt så länge skrivaren har samma namn i Windows). Exempel på skrivarobjekt:

{
  "id": 3,
  "name": "ZDesigner ZD421-203dpi ZPL",
  "driver": "ZDesigner ZD421-203dpi ZPL",
  "default": true,
  "state": "online",               // online | offline | deleted
  "capabilities": { "papers": { "100x150": [1000, 1500] }, "dpis": ["203x203"], "copies": 1 },
  "computer": { "id": 1, "name": "LAGER-PC", "state": "connected" }
}

Skapa utskriftsjobb

POST /api/v1/printjobs

Svarar med 201 och jobbet så fort det är köat. Om datorn är offline ligger jobbet kvar i kö (standard 14 dagar) och skrivs ut när klienten kopplar upp igen.

FältTypKrävsBeskrivning
printerIdintjaSkrivarens id från /printers.
contentTypestringjaraw_base64, raw_uri, pdf_base64 eller pdf_uri. raw = ZPL/EPL/annan råkod som skickas oförändrad till skrivaren. pdf renderas på lagerdatorn och skrivs ut via Windows-drivrutinen.
contentstringjaBase64 av dokumentet (för *_base64) eller en http(s)-URL som servern hämtar (för *_uri). Max 25 MB avkodat.
titlestringnejNamn i jobbloggen och i Windows utskriftskö, t.ex. ordernummer.
sourcestringnejFritext om avsändaren, t.ex. somnis.se.
qtyintnejAntal gånger jobbet skickas till skrivaren (1–100). Enda sättet att få flera kopior av ett raw-jobb – eller använd ^PQ i ZPL.
optionsobjectnejSe alternativ. Ignoreras vid raw-utskrift.
expireAfterintnejSekunder jobbet får ligga i kö innan det markeras expired. Standard 1 209 600 (14 dagar).
authenticationobjectnejFör *_uri: {"type":"BasicAuth","credentials":{"user":"…","pass":"…"}} eller {"type":"Bearer","credentials":{"token":"…"}}.

Header X-Idempotency-Key: <valfri sträng> skyddar mot dubbla jobb vid omförsök: samma nyckel ger 409 Conflict med det befintliga jobbets id.

Svar:

{
  "id": 128,
  "title": "Order 10234",
  "contentType": "raw_base64",
  "state": "new",
  "printer": { "id": 3, "name": "ZDesigner ZD421-203dpi ZPL" },
  "computer": { "id": 1, "name": "LAGER-PC" },
  "createTimestamp": "2026-09-04T10:12:44.000Z",
  "expireAt": "2026-09-18T10:12:44.000Z"
}

Övriga jobb-anrop

GET /api/v1/printjobs?limit=50&printerId=3&state=error&after=200

GET /api/v1/printjobs/{id}

GET /api/v1/printjobs/{id}/states
– historik med tidsstämplar.
DELETE /api/v1/printjobs/{id}
– avbryter ett jobb som inte hunnit skickas till datorn.

Alternativ (options) för PDF

NyckelTypBeskrivning
copiesintAntal kopior (1–999).
fit_to_pageboolSkala PDF-sidan så den passar etikettens utskrivbara yta (standard true).
paperstringNamn på pappersstorlek enligt skrivarens capabilities.papers, t.ex. "100x150". Utelämnas → drivrutinens standard.
rotateint0, 90, 180 eller 270 grader.
dpistringRenderingsupplösning, t.ex. "203x203". Standard: skrivarens upplösning.
pagesstringSidval, t.ex. "1", "1,3" eller "2-".
duplex, bin, color, collate, mediaAccepteras och skickas till klienten; stöd beror på drivrutinen.

Jobbstatus

stateBetydelse
newRegistrerat och köat på servern.
sent_to_clientHämtat av lagerdatorn.
doneLämnat till Windows utskriftskö / skrivaren. Därefter ansvarar skrivaren.
errorUtskriften misslyckades (se stateMessage), t.ex. skrivaren saknas eller drivrutinsfel.
expiredDatorn hämtade aldrig jobbet inom expireAfter.
deletedAvbrutet via API eller admin.

Rekommendation: skapa jobbet när ordern packas/etiketten skapas, spara jobbets id på ordern och visa status i ert system via GET /printjobs/{id} vid behov.

Felhantering

Fel returneras som JSON med HTTP-status ≥ 400:

{ "code": "PrinterNotFound", "message": "Skrivaren 99 finns inte." }

Vanliga koder: InvalidCredentials (401), InvalidRequest/InvalidContent/InvalidContentType/PrinterNotFound/ContentTooLarge/ContentDownloadFailed (400), NotFound (404), Conflict (409).

Kodexempel

curl – skriv ut ZPL

ZPL='^XA^FO50,50^A0N,40,40^FDOrder 10234^FS^FO50,110^BY3^BCN,100,Y,N,N^FD10234^FS^XZ'
curl -s https://print.lenbird.com/api/v1/printjobs \
  -H "Authorization: Bearer $LENBIRD_PRINT_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg c "$(printf '%s' "$ZPL" | base64 -w0)" \
        '{printerId: 3, title: "Order 10234", contentType: "raw_base64", content: $c, source: "somnis.se"}')"

curl – skriv ut en PDF-fraktsedel från URL

curl -s https://print.lenbird.com/api/v1/printjobs \
  -H "Authorization: Bearer $LENBIRD_PRINT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "printerId": 3,
    "title": "Fraktsedel 10234",
    "contentType": "pdf_uri",
    "content": "https://example.com/labels/10234.pdf",
    "options": { "fit_to_page": true, "copies": 1 }
  }'

PHP (WooCommerce / WordPress)

<?php
/**
 * Skickar en etikett till Lenbird Print. Returnerar jobb-id eller kastar Exception.
 * $content = ZPL-sträng (raw) eller PDF-binärdata.
 */
function lenbird_print(int $printerId, string $title, string $content, string $type = 'raw'): int {
    $apiKey = defined('LENBIRD_PRINT_KEY') ? LENBIRD_PRINT_KEY : getenv('LENBIRD_PRINT_KEY');
    $body = [
        'printerId'   => $printerId,
        'title'       => $title,
        'contentType' => $type === 'pdf' ? 'pdf_base64' : 'raw_base64',
        'content'     => base64_encode($content),
        'source'      => home_url(),
        'options'     => $type === 'pdf' ? ['fit_to_page' => true] : null,
    ];
    $response = wp_remote_post('https://print.lenbird.com/api/v1/printjobs', [
        'timeout' => 20,
        'headers' => [
            'Authorization'     => 'Bearer ' . $apiKey,
            'Content-Type'      => 'application/json',
            'X-Idempotency-Key' => 'order-' . $title,
        ],
        'body' => wp_json_encode($body),
    ]);
    if (is_wp_error($response)) {
        throw new Exception('Lenbird Print: ' . $response->get_error_message());
    }
    $data = json_decode(wp_remote_retrieve_body($response), true);
    $code = wp_remote_retrieve_response_code($response);
    if ($code === 409 && !empty($data['jobId'])) {
        return (int) $data['jobId']; // redan skickat
    }
    if ($code !== 201) {
        throw new Exception('Lenbird Print: ' . ($data['message'] ?? "HTTP $code"));
    }
    return (int) $data['id'];
}

// Exempel: skriv ut plocketikett när ordern går till "processing"
add_action('woocommerce_order_status_processing', function ($order_id) {
    $order = wc_get_order($order_id);
    $zpl = "^XA^CI28^FO40,40^A0N,45,45^FDOrder {$order->get_order_number()}^FS"
         . "^FO40,100^A0N,30,30^FD{$order->get_shipping_first_name()} {$order->get_shipping_last_name()}^FS"
         . "^FO40,160^BY3^BCN,120,Y,N,N^FD{$order->get_order_number()}^FS^XZ";
    try {
        $jobId = lenbird_print(3, 'Order ' . $order->get_order_number(), $zpl, 'raw');
        $order->add_order_note("Etikett skickad till lagret (Lenbird Print jobb #$jobId).");
    } catch (Exception $e) {
        $order->add_order_note('Etikett kunde inte skickas: ' . $e->getMessage());
    }
});

Node.js (18+)

const LENBIRD_PRINT_KEY = process.env.LENBIRD_PRINT_KEY;

export async function printLabel({ printerId, title, zpl, pdf, options }) {
  const body = {
    printerId,
    title,
    contentType: pdf ? "pdf_base64" : "raw_base64",
    content: Buffer.from(pdf ?? zpl).toString("base64"),
    options: pdf ? { fit_to_page: true, ...options } : undefined,
    source: "somnis.se"
  };
  const response = await fetch("https://print.lenbird.com/api/v1/printjobs", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${LENBIRD_PRINT_KEY}`,
      "Content-Type": "application/json",
      "X-Idempotency-Key": `order-${title}`
    },
    body: JSON.stringify(body)
  });
  const data = await response.json();
  if (response.status === 409 && data.jobId) return data.jobId;
  if (!response.ok) throw new Error(`Lenbird Print: ${data.message}`);
  return data.id;
}

// Kolla status
export async function jobStatus(id) {
  const response = await fetch(`https://print.lenbird.com/api/v1/printjobs/${id}`, {
    headers: { Authorization: `Bearer ${LENBIRD_PRINT_KEY}` }
  });
  return response.json(); // { state: "done" | "new" | ... }
}

Tips för Zebra/ZPL

Lenbird Print · Aurelius Group AB