Documentation / API

The API

Connecting a ticket system, a script or a monitoring tool: how to sign in, find a device and read its state.

Signing in with a key

Another system does not sign in with a person's username and password. A superadmin creates an API key on the API Keys page, and every request carries it:

curl -H "X-API-Key: mikr_…" http://your-manager:3000/api/devices

Use your HTTPS address instead if the manager has one. A client that can only set an Authorization header can send the same key as Authorization: Bearer mikr_….

The key is shown once, when you create it. It has its own role and its own list of sites, set the same way as a user's, and it can have an expiry date. A key is a viewer, an operator or an admin — never a superadmin, so no key can reach user accounts or issue more keys. Every request is answered as that key: a key limited to one site lists only that site's devices, and a device outside it is refused. For reading state, which is everything on this page, a viewer key is enough. See Users & Access for what each role allows.

One thing to know before scoping a key: an admin key limited to sites also sees the devices that belong to no site at all, where a scoped operator or viewer key sees none of them.

Give each integration its own key. Revoking it then cuts off exactly one system and leaves the others working.

Finding a device

Every device has an id, and the requests below take that id — its name or its address is not accepted in place of it. A ticket usually names a device instead, so start by fetching the list:

GET /api/devices

It returns every device the key can see, sorted by name. There is no search parameter: match on the fields your ticket carries, then keep the id. The fields most useful for that:

FieldWhat it holds
idWhat the other requests take.
nameThe name given to the device in the manager.
hostThe IP address or hostname the manager connects to.
status.identityThe RouterOS identity, as set on the router itself.
tags, siteIdTags and the site the device belongs to.

Add ?grouped=true to get the same devices grouped under their sites. The answer is then an object holding sites, each of which carries its own devices; anything belonging to no site comes last, in a group named Ungrouped.

Reading a device

GET /api/devices/{id}

Returns what the manager knows from its last poll, without contacting the device. The status object is where diagnosis starts:

FieldWhat it holds
status.onlinetrue if the last poll succeeded, false if it failed, null if the device has not been polled yet.
status.offlineSinceWhen it stopped answering.
status.lastCheckedWhen the manager last tried to poll it. A failed poll writes this too, so a recent timestamp means the manager is still trying, not that the device answered — that is what status.online is for.
status.uptime, status.cpuLoad, status.freeMemory, status.totalMemory, status.temperatureThe basics from that poll.
status.routerOsVersion, status.latestRouterOs, status.modelWhat it runs, what is available on its channel, and what it is.

These ask the device directly, so each one takes as long as a round trip to the router:

RequestReturns
GET /api/devices/{id}/interfacesPorts in interfaces, and the neighbours discovered on them in neighbors.
GET /api/devices/{id}/routesHow large the routing table is, not the routes themselves: total and a count per protocol in protocols, with ipv6Total and ipv6Protocols beside them.
GET /api/devices/{id}/dhcp-leasesDHCP leases in leases, and how full each pool is in pools.
GET /api/devices/{id}/wireless-clientsConnected wireless clients, in clients.

A router that cannot be reached answers 502, with error carrying the reason and the list it would have filled left empty beside it. An empty list with 200 means the opposite: the device answered and has nothing of that kind to report. Reading the status code is enough to tell the two apart.

History comes from the manager's own records instead:

GET /api/devices/{id}/health-history?range=24h
GET /api/devices/{id}/health-history?range=24h&metric=cpu-load

Without metric it lists the metrics that have samples in that range. With one, it returns points carrying ts, avg, min and max. The range is one of 1h, 6h, 24h, 7d or 30d, and anything else is refused rather than rounded to the nearest.

Logs

GET /api/syslog?deviceId={id}&limit=100

Syslog the manager has collected from the device, newest first, in rows. It narrows further with search for text, topic, and maxSeverity — a number from 0, emergency, to 7, debug, keeping that level and everything more severe. siteId, since and until work here too, the last two as ISO timestamps. limit defaults to 200 and goes up to 1000; to walk further back, send the oldest receivedAt you were given as before and ask again. The device has to be sending its log to the manager; Logs explains how to set that up.

A device in a site the key cannot see is not an error on this request: the answer is an empty rows.

GET /api/syslog/export?deviceId={id}&format=csv&tz=Europe/Warsaw

The same entries as a file, oldest first, for a scheduled dump or an archive. format is csv or txt. tz is an IANA time zone for the local time column, and UTC is used when it is missing. The filters above all apply. There is no limit: one export holds up to the newest 100,000 entries, and when it stops there the response carries X-Export-Truncated with that ceiling as its value.

When a request fails

Errors come back as JSON with an error field and the usual status code:

CodeMeans
401The key is missing, mistyped, revoked or past its expiry date.
403The key's role does not allow this request, or the device is in a site the key is not scoped to.
404There is no device with that id.
422The device is disabled in the manager, so requests that ask the device directly are refused.
502The manager could not reach the device, so the reading could not be taken. The body still carries the field the reading would have arrived in, empty, alongside error.

Missing something your integration needs? Write to support@mikr.app and say what it has to do.