Every Indonesian top-up site has the same little feature. You type your Mobile Legends user ID and your zone, and before you pay, it shows you your username. “Doedja” or whatever. It’s the “yeah, ID’s valid, that’s me, charge my card” confirmation.
I was poking around one of them last week and got curious: who’s actually answering that query? Because none of these sites are connected to Moonton. They’re resellers. They’re definitely not running their own validator.
So I opened the network tab and, predictably, they’re all hitting the same handful of reseller backends and parroting the response back. Every top-up site in Indonesia is doing the same scrape. Only a small handful packages it as an API.
So I built it.
whoplays.doedja.com. 49 games so far (and growing), one endpoint, free tier 30/min with an API key. You POST a game slug and some input, you get a username back.
POST /api/check
{ "game": "mobile-legends", "input": { "userId": "...", "zoneId": "..." } }
If you clicked the link, you’ve noticed the site looks like a Unix man page. System monospace, no web fonts, no rounded corners, no shadows, no animations. Two colors: text and links. That’s on purpose. I wanted to ship as simple as I could get away with, partly to move fast, partly because the UI may as well match what it’s wrapping. You’ll either appreciate it or close the tab.
Why I built it
Two reasons.
First, this is my first real shot at building a SaaS end-to-end. I’ve shipped plenty of side projects but nothing with the actual SaaS surface area: auth, billing, rate limiting, analytics, docs, revocable API keys. I wanted to feel the whole shape of it. WhoPlays is my test.
Second, I saw the gap and wanted to know if I could close it cleanly.
Once I started digging, a bonus reason showed up: doing this yourself is actually kinda annoying.
Reseller backends don’t fail like proper APIs do. They degrade silently. HTTP 200 with a broken shape. A field rename with no changelog. A captcha that appears out of nowhere. A cookie that used to be optional and suddenly isn’t. If you’re scraping one of them directly, you’re signing up to babysit that flakiness forever. And if you want a fallback for when the primary goes down (which it will), now you’re babysitting four scrapers instead of one.
That’s the pitch. I already did the babysitting.
Why you’d use this instead of rolling your own
- Free up to 30/min. Probably enough for a Discord bot or a small tournament page. Pro is Rp 49,900 for 30 days at 1,200/min (one-time, no auto-renew) if you need more.
- Auto-fallback. If one backend has a moment for MLBB specifically, lookups still resolve. You don’t debug it, I do.
- Routes around flaky sources. The dispatcher watches its own health telemetry and reorders sources per game. When one goes flaky, a fallback takes over on its own. No config.
- One response shape, forever. No matter which upstream answered, you get the same
{ ok, game, username }envelope. I absorb all the field-rename whiplash. - Revocable API keys. Not a password. Rotate whenever.
If you genuinely enjoy maintaining scrapers, go forth. But if you just need a username to confirm a top-up or validate a tournament entry, skip the yak shave.
Status
Live at whoplays.doedja.com. Zero users as of writing. I pushed the first commit 48 hours ago. Free tier works without a credit card, just an email.
Treat this as a test. I’m genuinely not sure if anyone wants it, but I’m going to keep poking at the shape of the problem until I find a fit or convince myself there isn’t one. If you’re building something that validates player IDs, try it. Free tier’s generous and I’d rather hear what you’d actually pay for than guess.
Docs at /docs.