---
title: "MikroTik Native API Client"
description: "MikroTik Native API Client: MikroTik's binary router API, in 137 lines of standard-library Python."
url: https://www.joekarlsson.com/work/mikrotik-api-client/
---

![A MikroTik API login sentence written to the wire one word at a time, /login, =name=admin and =password=secret, each with its length byte, then a zero byte, and RouterOS answering !done](https://www.joekarlsson.com/images/projects/mikrotik-api-client/thumb-6cc55f0c.webp)

# MikroTik Native API Client

MikroTik's binary router API, in 137 lines of standard-library Python.

2026

[Read why I built it](https://www.joekarlsson.com/blog/implementing-mikrotik-binary-api-protocol-in-python/)

My homelab's 10G backbone is a MikroTik CRS317 switch, and I wanted to change its bonds, DHCP and firewall rules from scripts instead of typing into SSH. RouterOS has an API on port 8728 that speaks its own binary protocol over raw TCP: sentences made of words, each word led by its length, each sentence ended by a zero byte.

I wrote the protocol myself instead of using a library. The Python ones are heavy, and I only understand a byte-level format once I've built it. The length encoding turned out to be the trick UTF-8 uses, where the first byte's high bits say how many more bytes follow. The client came out at 137 lines with no dependencies, small enough to call from a cron job.

## How it's made

Python · Binary Protocol · MikroTik · Networking

It uses only `socket` and `struct`: it logs in, sends each command as a sentence, and reads `!re` replies until `!done`, or `!trap` for an error. Any RouterOS command works from the command line with no code changes. [How it works, byte by byte](https://www.joekarlsson.com/blog/implementing-mikrotik-binary-api-protocol-in-python/).

_Diagram: How the MikroTik API client talks to RouterOS. The Python script, using only socket and struct, opens a raw TCP connection to RouterOS on port 8728. It sends a /login sentence with =name= and =password= words, and RouterOS answers !done. Then it sends a command such as /interface/bonding/print, and RouterOS answers with one !re sentence per record, then !done, or !trap on an error. On the wire, each word goes out as its length and then its bytes: 06 and the six bytes of /login, 0b and the eleven bytes of =name=admin, and a 00 byte ends the sentence. The length byte works like UTF-8: its high bits say how many more length bytes follow._

## Lineage

Also about the wire

[Guide to Client-Server Communication](https://github.com/JoeKarlsson/complete-guide-to-client-server-communication): Every way a client and server communicate - HTTP, WebSockets, SSE, GraphQL, gRPC, and more. A complete reference guide with examples. 2016 · 43 stars · Node.js, HTTP, WebSockets

[Source](https://github.com/JoeKarlsson/complete-guide-to-client-server-communication) · [Blog Post](https://www.joekarlsson.com/blog/complete-guide-node-client-server-communication/)

[← All works](https://www.joekarlsson.com/work/)
