Hyundai Bluelink blocked (error 9035)? Getting your EV's state of charge from the official Pleos API
If you have your Hyundai, Kia or Genesis connected to Home Assistant, evcc or a script of your own, you have probably seen this since mid-October 2026: error 9035. From one day to the next, no state of charge came through. For me a whole system depended on it – my energy management JG Energy needs the Ioniq 5’s state of charge to run surplus charging and charge plans.
Here’s what happened, how I solved it with the official Pleos Vehicle Data API, and what to watch out for.
What happened
Almost every Hyundai and Kia integration uses the same unofficial interface: it pretends to be the smartphone app when talking to the Bluelink servers. In Python this is usually the hyundai_kia_connect_api library.
On 13 October 2026, Hyundai Europe started checking every request for a signature header that only the official app could generate. Everyone else got error 9035. The app itself kept working – the account wasn’t blocked, only third-party programs were locked out.
Two days later, version 4.35.3 of the library arrived and reproduces the signature. Bluelink has worked again since. But it’s a cat-and-mouse game: Hyundai can change the check again at any time.
The official route: EU Data Act and Pleos
Under the EU Data Act, manufacturers have to make vehicle data available to owners. Hyundai Motor Group (Hyundai, Kia, Genesis) does this through Pleos and its Vehicle Data API. It’s free for private users in Europe.
Among other things, the API returns:
| Endpoint | Content |
|---|---|
/batteries | state of charge, charging state, cable, target SoC, remaining time |
/powertrains | powertrain, range |
/driving | driving status, odometer |
/locations | location |
/status | sensor-based vehicle status |
Set your expectations right: the API returns the data the car last reported to Hyundai. It does not wake the car, and there are no commands such as “set charge limit” or “start climate control”.
Setup step by step
- In the Pleos Playground (pleos.ai/playground) open My Vehicle Data API and pick the manufacturer.
- Sign in with the Bluelink account of the main user – the account the car is registered to in the app.
- After signing in, the Playground shows a client ID and a client secret. Store both safely, e.g. in a JSON file outside any web directory.
Pitfall #1: the wrong account. Our Ioniq is registered to another family member. My browser was still signed in to my own Hyundai account, and the Playground created the key for that account without asking. The key works – it just has no vehicle attached. Only a key generated with the main user’s account returns data.
Pitfall #2: 90 days. The key is valid for 90 days and is revoked automatically afterwards. The Playground shows the validity period. Set a reminder right away – or, as JG Energy does, test the connection daily so an expired key shows up immediately.
Fetching data
Two steps: first exchange client ID and secret for a short-lived access token, then use it to fetch data.
# 1. Get an access token
curl -s -X POST https://api.pleos.ai/v1/auth/personal-token \
-H "Content-Type: application/json" -H "Brand: hyundai" \
-d '{"clientId":"<CLIENT_ID>","clientSecret":"<CLIENT_SECRET>"}'
# → { "data": { "accessToken": "eyJ..." } }
# 2. Fetch charging status
curl -s https://api.pleos.ai/v1/vehicles/<VIN>/batteries \
-H "Brand: hyundai" -H "Authorization: Bearer <ACCESS_TOKEN>"
The fields that matter for charge control (as seen in my tests with an Ioniq 5):
| Field | Meaning |
|---|---|
charge.stateOfCharge | state of charge in % |
charge.plugin | "connected" when the cable is plugged in |
charge.charging | currently charging |
charge.targetStateOfCharge.standard | AC charge limit (.quick = DC) |
charge.remainTime | remaining charge time in minutes |
distanceToEmpties (type EV) in /powertrains | range |
odometer.value in /driving | odometer |
timestamp per endpoint | when the car reported this data |
Not all field names are officially documented. I therefore save the last raw response to a file – that has helped with debugging more than once.
Lessons from running it
Expired tokens return 403, not 401. The access token is only valid for a limited time. In my setup the API answers an expired token with HTTP 403 – a status code you’d rather expect for missing permissions. So my client initially didn’t fetch a new token and reported an error. The fix: on 401 and 403, fetch a new token once and retry. On top of that I fetch a fresh token before each request if the current one is older than 30 minutes.
The state of charge is only as fresh as the car’s last report. While charging, the Ioniq only reports at longer intervals. For a smooth display, JG Energy extrapolates: last real state of charge plus the energy the wallbox has measured since, divided by the learned battery capacity. But the decision to end a charge is always based on a real value – or left to the car itself.
Some things are missing. Compared to Bluelink, Pleos lacks the current charging power, the 12 V battery and the charge flap. And since the API is read-only, you can neither wake the car nor set the charge limit.
My setup today
Since Bluelink works again, I use both:
- Bluelink is the primary source – it can wake the car and set the charge limit.
- Pleos steps in automatically when Bluelink fails. JG Energy tests the Pleos connection once a day so an expired key doesn’t go unnoticed until it’s needed.
If all you need is the state of charge and you’re tired of the cat-and-mouse game, Pleos alone will serve you well. evcc now supports the interface too (“Hyundai EU Data Act”).
Conclusion
The EU Data Act delivered something very practical here: an official, free and stable interface to your own vehicle data. It’s read-only and not quite as current as the app – but it doesn’t simply break because a manufacturer changes something on its servers overnight.
Links