DEV Community

Inioluwa Adebayo
Inioluwa Adebayo

Posted on

I built a WhatsApp bot to check WiFi balances, and TP-Link's own API fought me the whole way

I run WiFi for a few hostels using TP-Link Omada controllers. Wanted customers to buy data and check their remaining balance straight from WhatsApp, no need to message me directly.

Sounded simple. It was not.

Attempt 1: TP-Link's official Open API

TP-Link has a real, documented API for this. OAuth2, client credentials mode, the whole thing. I set it up exactly the way their own tutorial says to: created an app, grabbed the Client ID, Client Secret, and Omada ID straight from their dashboard.

Every single request came back with the same error:

{"errorCode": -7131, "msg": "Controller ID not exist."}
Enter fullscreen mode Exit fullscreen mode

Using the exact ID they gave me. I tried v1. I tried v2. I tried the ID as a query param instead of in the body. Same error every time.

Went looking and found other people hitting this exact same wall on TP-Link's own community forum, including one thread where a TP-Link staff member replied and it still did not get resolved. This was not me making a mistake. It is a known, unresolved bug on their end.

Attempt 2: Operator accounts

Omada has a separate "Hotspot Operator" account type, lighter access than a full admin login. Thought maybe this would sidestep the issue since it uses a different login system entirely.

Created operator accounts across all 5 of my controllers. Could not find a working login portal for any of them. Turns out the operator login URL pattern only works for locally hosted controllers, not cloud hosted ones like mine. Found someone else with a cloud setup hitting the identical dead end.

Two official paths, two dead ends.

Attempt 3: reverse engineering their own dashboard

At this point I stopped trying to use their API and just watched what their own website does.

Opened DevTools, logged into the Omada dashboard myself, and captured every request my browser made. Turns out logging in is not one API call. It is five separate steps: hit the portal, get redirected to an authorize URL, get a session code, post credentials with that session code, exchange an authorization code for a session, and confirm the session.

None of this is in their public docs. I only know it because I watched my own browser do it.

The bug that took hours to find

Got the login working. Cookies, csrf token, everything looked correct. But every single voucher lookup came back with:

{"errorCode": -1200, "msg": "You have been logged out of the controller."}
Enter fullscreen mode Exit fullscreen mode

Session looked valid. Controller said otherwise. For hours I could not figure out why.

Turned out there is a sixth step I was missing. After you get your session cookies, the dashboard makes one more call to confirm the login:

GET /api/v1/central/account/login-status
Enter fullscreen mode Exit fullscreen mode

Skip it, and your session looks complete on paper but was never actually finished setting up on TP-Link's end. No controller will accept it.

One missing API call. That was the entire bug.

Where it landed

Fixed that, and the balance checker started working across all 5 hostel locations. Customer sends their voucher code on WhatsApp, gets their remaining data and days left back in under a second.

A second bug, right after the first

Once the session bug was fixed, a real controller went offline (an actual power/network outage at one location, nothing to do with the session). It threw a different error:

{"errorCode": -7200, "msg": "Omada Controller is offline or does not exist."}
Enter fullscreen mode Exit fullscreen mode

My fix for the first bug was catching this one too, and treating an offline controller the same as a dead session, wiping and retrying the whole login instead of just skipping that one controller. Had to split those two error types apart so one hostel's outage does not take down the balance check for the other four.

The actual takeaways

  1. A 200 status code is not success. TP-Link, like a lot of APIs, buries real errors inside a 200 response body. Check the body, not just the status line.
  2. "It looks logged in" is not the same as "it is logged in." A session can have valid cookies and a valid CSRF token and still not be fully provisioned server-side, if you skip whatever the frontend does after the redirect to actually finish the handshake.
  3. Not every error that sounds like a session problem is a session problem. Conflating "offline controller" with "dead session" meant one outage could wrongly nuke a session that was working fine everywhere else.
  4. If an official API is broken, the product's own frontend is the real documentation. DevTools and a Network tab told me more in twenty minutes than the official docs did in two days.

If you run Omada

If you manage hostels, apartments, offices, or any business on Omada controllers and want your customers checking balances (or buying data) on WhatsApp instead of messaging you directly, this is exactly what I built and now run. Happy to set it up.

Find me on X or TikTok: @thebotguy_

Top comments (0)