Skip to content

API

The API is in development and may change before the first release.

The REST API lives at https://<your-control-center>/functions/v1/api/v1. Every request needs an API key from the control center:

Authorization: Bearer mk_live_…
Content-Type: application/json

Errors always have the same shape:

{ "error": { "code": "label_not_found", "message": "No label with id …" } }

Find something on the floor

POST /locate makes every label bound to a record blink.

curl -X POST https://your-server/functions/v1/api/v1/locate \
  -H "Authorization: Bearer mk_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "entity": { "doctype": "Warehouse", "name": "KIT 164" }, "preset": "locate" }'
{ "labels": [{ "label_id": "3f0c…", "request_id": "9b1e…" }] }

Presets set colour and timing. You can override color, duration_s, on_ms, off_ms and brightness.

PresetColourPatternRuns for
locatewhitefast blink60 s
pickgreenlong on, short off5 min
attentionyellowslow blink2 min
alertredvery fast blink60 s
ackgreenone short flash1 s
offturns the LED off

Labels

MethodPathWhat it does
GET/labelsList labels, filter by site_id, status or text
GET/labels/{id}One label with its binding and current content
PATCH/labels/{id}Rename a label or move it to another site
PUT/labels/{id}/bindingBind a label to a record and a template
DELETE/labels/{id}/bindingRemove the binding
PUT/labels/{id}/contentSet content by hand: a template and its data
POST/labels/{id}/ledBlink one label
POST/refreshRe-read bound records now, for some labels or all

Bindings

A binding says what a label represents and where its data comes from. This one shows the open work order that is packed in kitting box KIT 164:

{
  "entity": { "system": "erpnext", "doctype": "Warehouse", "name": "KIT 164" },
  "template_id": "…",
  "empty_template_id": "…",
  "resolver": {
    "kind": "erpnext-query",
    "doctype": "Work Order",
    "filters": [["kitting_box", "=", "{{entity.name}}"], ["status", "not in", ["Completed", "Cancelled"]]],
    "fields": ["name", "item_name", "qty", "expected_delivery_date", "priority"],
    "map": { "wo": "name" }
  }
}

When no work order matches, the label shows empty_template_id, for example "Box free".

Templates

Templates are HTML fragments with Mustache placeholders, laid out with flexbox. Every value is escaped. Two extra tags exist:

  • <mk-qr value="{{wo}}" size="96" /> draws a QR code.
  • <mk-fit max="22" min="12">…</mk-fit> shrinks long text until it fits.

Colours are limited to what the panel can show: white, black, red and yellow (red and yellow only on colour panels).

Webhooks

Subscribe with POST /webhooks and a list of events. Each delivery is signed:

X-Merkora-Signature: t=1760000000,v1=<hex HMAC-SHA256 of "t.body">

Check the signature with your subscription secret and reject anything older than five minutes.

EventWhen
button.pressedSomeone pressed the button on a label
content.displayedA label confirmed it shows new content
content.failedA label could not be updated after retries
label.offlineA label stopped answering
label.battery_lowA label's battery is running low
led.doneA blink request was delivered
{
  "id": "…",
  "type": "button.pressed",
  "at": "2026-10-09T09:14:03Z",
  "org_id": "…",
  "data": {
    "label_id": "…",
    "label_name": "KIT 164",
    "entity": { "system": "erpnext", "doctype": "Warehouse", "name": "KIT 164" },
    "event": { "button": 0, "kind": "short" }
  }
}

merkora

Merkora is made by Newmatik, an electronics manufacturer in Germany. Software and firmware will be published under Apache-2.0 and the hardware under CERN-OHL-W-2.0.