Skip to main content
Gary
Rank 1
Rank 1
March 9, 2017
Solved

Can we get access to the OVO energy online account API to download our smart meter usage data?

  • March 9, 2017
  • 227 replies
  • 36559 views

Hi Ovo,

I wondered whether the API that powers your live and historical usage page in the account menu is something you could look into opening up a bit so we can freely access our raw data and also perhaps it may stimulate some interesting community projects?

For instance (more sport related), Strava and Fitbit.

Best answer by g-de

Updated on 14/08/25 by Abby_OVO

 

Tim_OVO: “We love seeing the innovative ways our customers are using tech to help monitor and manage their energy usage. It’s inspiring us to think about ways to do energy differently. We know some customers have been using some of the application programming interface (APIs) behind our public facing services. While we’re OK with that, we do need to make you aware of a couple of things.

 

These APIs are designed to be used by OVO teams only, and aren't public facing. There are some downsides to using APIs that aren't for the public, and we wanted to let you know what these are. Behind the scenes, OVO uses APIs to share and update information between systems that power your bills and your online account. This is done in partnership with Kaluza, the tech company that’s part of the OVO family. They’ve built the billing platform designed to put our customers in the driving seat of their energy usage. 

 

These internal APIs are intended for use by Kaluza and its clients, who are energy retailers like OVO, rather than customers. Because of this, there’s no support for them being used anywhere else, which means they may be discontinued with no notice when we update our products and services. 

 

OVO Energy and Kaluza need to be able to monitor these APIs, and may block access if there's any problems in the future.

 

We know some customers may have put time and effort into developing solutions that use these API. So, now that you know the risks, we want to hear from you on how you’re using the APIs and the problems you’re solving with your DIY approach. 

 

Is there anything you’d like to see from OVO to help you monitor and manage your energy better? Leave a comment below to tell us.”

 

can you help me understand if the links above allow users to access raw data as if from an API?

I can certainly give it a go.

 

Firstly, big thanks to Timmo and other contributors for developing the library. All thanks go to them and links to buy them a coffee for their effort can be found on PyPi or GitHub:

https://pypi.org/project/ovoenergy/
https://github.com/timmo001/ovoenergy

 

I assume the way the library was developed this was to reverse engineer the My OVO website. That is, browse the website as normal and and monitor the traffic to see what OVO URLs and APIs it uses. Assuming this is the case, one of these URLs (get account IDs) already seems to be different but the library is still working for the moment. The APIs being used are not officially supported outside of the website, so first, a warning that any changes to the My OVO website may break the library.

 

For anyone using Python, you should be able to include the ovoenergy library and look at https://github.com/timmo001/ovoenergy/blob/master/ovoenergy/cli.py for how to use it.

 

For replicating this in other languages, the process seems to be as follows:

  1. Login by sending a POST request to https://my.ovoenergy.com/api/v2/auth/login with the following JSON in the body:
    {
    "username": "...",
    "password": "...",
    "rememberMe": true
    }

    From the response, save the cookies to use in all future requests.

  2. Next, send a GET request to https://smartpaym.ovoenergy.com/api/customer-and-account-ids . Be sure to save the items in the “accountIds” property (usually only one item).
  3. Finally, make a GET request to https://smartpaym.ovoenergy.com/api/energy-usage/daily/{accountId}?date={yyyy-MM} where {accountId} is the value from the previous request and {yyyy-MM} is the month in the format 2020-08.

You can also get monthly or half-hourly usage using the following URLs similar to step 3:

As mentioned above, if this is wanted for Home Assistant, the integration was added in version 0.114 (https://www.home-assistant.io/integrations/ovo_energy/).


Unfortunately the data only goes up to the end of the previous day as OVO no longer provide real-time data:

 

227 replies

Jeffus
Rank 20
Rank 20
December 8, 2022

If you have previously downloaded the Bright app. 

https://play.google.com/store/apps/details?id=uk.co.hildebrand.brightionic

https://itunes.apple.com/us/app/bright/id1369989022?ls=1&mt=8

 

Then you can use the same login details on their beta website to download a csv as a workaround. 

http://www.smarttariffsmartcomparison.org/login

 

Firedog
Super User
Super User
December 8, 2022

The National Grid record data in GMT throughout the year, even when it’s BST but some sites record data an hour later than the clock time…

Tim_OVO wrote:

… I don’t know how this impacts the online account. My assumption is that the online account uses a system to correctly shift usage blocks in terms of local time.

 

It looks like there’s a semi-manual kludge to shift the usage figures by an hour at the start and end of BST. This is only for presentation, though; there are still 48 half-hourly readings for each day as the consumption figures show. Here are my figures for 30 October 2022 as displayed online:
  

 

So, only 46 readings usage figures displayed, starting at 01:00 GMT. It all comes out in the wash, of course, because the readings sequence is unbroken. Just for comparison, here are the data underlying the displayed figures (for the first 7.5 hours):
 

[Extracted from https://smartpaymapi.ovoenergy.com/usage/api/half-hourly/3198737?date=2022-10-30. To get your own JSON data, substitute your OVO account no. for 3198737 in the URL, and open the page in the same browser session as one where you’re signed in at account.ovoenergy.com so the page can find your access token.] 

 

 

Noel | I have no official status; I'm just a volunteer who comes here to help other customers. My gear: Aclara SGM 1416-B Electricity-only E7 meter; Chameleon IHD3-PPMID-AAA | It may look as if I know what I’m talking about, but don’t let that fool you. |
Tim_OVO
OVO Staff
OVO Forum Legend
December 9, 2022
Carbon neutral - we need a community to get there! My green tech: Aclara SGM 1411-B smart meter, Chameleon IHD6
Firedog
Super User
Super User
December 10, 2022

@Firedog is this an OVO public API? 

Sure. That’s where the data come from to populate the various bits of the account site. Here are a few more sources that work for me:

https://smartpaymapi.ovoenergy.com/usage/api/monthly/{account}?date=2022

https://smartpaymapi.ovoenergy.com/pace/recommended-dds/v1/{account}/projected-costs?limitNextYear=true

 https://smartpaymapi.ovoenergy.com/rlc/rac-public-api/api/v5/supplypoints/electricity/{MPAN}/meters/{MSN}/readings?from=2016-09-09

This isn’t real-time; I think the newest data are from the last daily refresh, usually shortly after 01:00 each day. So today’s data won’t ever be available.

 

[What I’d really like is for an Excel guru to tell me how to include the authentication refresh-token into a query so I could push the JSON data directly into a worksheet.]  

Noel | I have no official status; I'm just a volunteer who comes here to help other customers. My gear: Aclara SGM 1416-B Electricity-only E7 meter; Chameleon IHD3-PPMID-AAA | It may look as if I know what I’m talking about, but don’t let that fool you. |
Newcomer
December 23, 2022

You need to go through the login and cache the cookies to get access to the smart meter API.  I’ve got this all coded in Node-RED Javascript.  I dump data into a MySQL D/B.  Here are the URIs that I use:

https://${MYOVO}/login
https://${MYOVO}/api/v2/auth/login
https://${PAYMAPI}/first-login/api/bootstrap/v2/
https://${PAYMAPI}/orex/api/plans/${msg.account}
https://${PAYMAPI}/rlc/rac-public-api/api/v5/supplypoints/electricity/${msg.mpxn}/meters/${msg.msn}/readings?from=${context.get('dailyStart')}
https://${PAYMAPI}/usage/api/half-hourly/${m.account}?date=${m.start}

Except for the 1st login, these all return a JSON payload that is easy to walk in Javascript.   I use the plans request to get the MSN and MPXN fields as well as current peak, off-peak and standing charges. The readings request gives me daily peak and off-peak usage which can be used to calculate charges.  Looping around the half-hourly request give the daily breakdown.

The API is the same for gas and electricity, though I have an electric-only low energy house so only download electrical data.  

Incidentally we are currently running at 80% off-peak use.

Rank 5
December 23, 2022

Thanks to you all for taking the time to explain this to me….sadly it’s not a language I’m familiar so it’ll take a few days to work it all out….I’ll persevere though. Thanks again.

Newcomer
February 3, 2023

@Tim_OVO @g-de Is there a way to parse the balance from the API? I have not seen that in the documentation and I failed by just playing around with random URLs that could potentially show it in my Python script.  

Newcomer
February 3, 2023

@Tim_OVO @g-de Is there a way to parse the balance from the API?

Are you just wanting the “Today’s balance” section from the home page?

Using the network tab of browser dev tools is the simplest way to reverse engineer the API.

Best I can see is that it uses a POST request to:

https://smartpaymapi.ovoenergy.com/bast/api/graphql

With the following body:

{
"query": "\nfragment FuelFields on BillingFuel {\n consumption {\n rates {\n rate {\n pence\n }\n cost {\n pounds\n }\n kwh\n openingRead\n openingReadType\n intermediateReads {\n date\n read\n readType\n }\n closingRead\n closingReadType\n startDate\n endDate\n friendlyLabel\n }\n }\n standing {\n netCharge {\n pounds\n }\n rates {\n rate {\n pence\n }\n startDate\n endDate\n days\n }\n }\n}\n\nfragment PeriodFields on SelectedPeriod {\n next\n previous\n data {\n electricity {\n ...FuelFields\n }\n gas {\n ...FuelFields\n }\n upgrades {\n description\n grossCharge {\n pounds\n }\n initialGrossCharge {\n pounds\n }\n startDate\n endDate\n taxRate\n }\n transactions {\n description\n netCredit {\n pounds\n }\n taxRate\n }\n payments {\n date\n description\n credit {\n pounds\n }\n }\n start\n openingBalance {\n pounds\n }\n end\n closingBalance {\n pounds\n }\n totalCharge {\n grossCharge {\n pounds\n }\n netCharge {\n pounds\n }\n vatCharge {\n pounds\n }\n }\n energyCharge {\n pounds\n }\n isStatementAvailable\n }\n}\n\nquery Period($id: String!, $index: Int!) {\n billingSummary(id: $id) {\n lastUpdated\n billablePeriod(periodIndex: $index) {\n ...PeriodFields\n }\n }\n}\nquery LatestPeriod($id: String!) {\n billingSummary(id: $id) {\n lastUpdated\n latestPeriod {\n ...PeriodFields\n }\n }\n}",
"operationName": "LatestPeriod",
"variables": {
"id": "<account-number>"
}
}

Remember to insert your account number. The balance should then be at data > billingSummary > latestPeriod > data > closingBalance > pounds. A negative number looks to indicate in debit.

It should be possible to tune the query in the body to only pull back the desired information, but I’m not familiar with graphql.

Newcomer
February 3, 2023

Best I can see is that it uses a POST request to:

https://smartpaymapi.ovoenergy.com/bast/api/graphql

 


That’s great. I ll try that

Newcomer
February 3, 2023

 

Just an additional question. I have tried that:

 

headers = {"Content-Type": "application/graphql"}

body = {
"query": "\nfragment FuelFields on BillingFuel {\n consumption {\n rates {\n rate {\n pence\n }\n cost {\n pounds\n }\n kwh\n openingRead\n openingReadType\n intermediateReads {\n date\n read\n readType\n }\n closingRead\n closingReadType\n startDate\n endDate\n friendlyLabel\n }\n }\n standing {\n netCharge {\n pounds\n }\n rates {\n rate {\n pence\n }\n startDate\n endDate\n days\n }\n }\n}\n\nfragment PeriodFields on SelectedPeriod {\n next\n previous\n data {\n electricity {\n ...FuelFields\n }\n gas {\n ...FuelFields\n }\n upgrades {\n description\n grossCharge {\n pounds\n }\n initialGrossCharge {\n pounds\n }\n startDate\n endDate\n taxRate\n }\n transactions {\n description\n netCredit {\n pounds\n }\n taxRate\n }\n payments {\n date\n description\n credit {\n pounds\n }\n }\n start\n openingBalance {\n pounds\n }\n end\n closingBalance {\n pounds\n }\n totalCharge {\n grossCharge {\n pounds\n }\n netCharge {\n pounds\n }\n vatCharge {\n pounds\n }\n }\n energyCharge {\n pounds\n }\n isStatementAvailable\n }\n}\n\nquery Period($id: String!, $index: Int!) {\n billingSummary(id: $id) {\n lastUpdated\n billablePeriod(periodIndex: $index) {\n ...PeriodFields\n }\n }\n}\nquery LatestPeriod($id: String!) {\n billingSummary(id: $id) {\n lastUpdated\n latestPeriod {\n ...PeriodFields\n }\n }\n}",
"operationName": "LatestPeriod",
"variables": {
"id": accountIds
}
}

response = requests.post(url, json={'query': body}, headers=headers,cookies=cookies)

print(response.status_code)
print(response.json())

but I am getting an 401 with a message 

'OAuth plugin - No refresh_token present'

I have tried removing the headers and I am still getting the same error