Severn Trent Smart Water Meter

My online account view uses a GraphQL API to fetch the data. It makes a curl request with a JSON object:

{
  "query": "query MeterReadings($accountNumber: String!, $activeFrom: DateTime) {
    account(accountNumber: $accountNumber) {
      properties(activeFrom: $activeFrom) {
        activeWaterMeters {
          id
          numberOfDigits
          readings(first: 50, excludeHeld: true, excludeQuarantined: true) {
            edges {
              node {
                valueCubicMetres
                readingDate
                source
              }
            }
          }
        }
      }
    }
  }",
  "variables": {
    "accountNumber": "A-********",
    "activeFrom": "2025-08-18T11:39:34.944Z"
  },
  "operationName": "MeterReadings"
}

and returns

{
    "data": {
        "account": {
            "properties": [
                {
                    "activeWaterMeters": [
                        {
                            "id": "*******",
                            "numberOfDigits": 5,
                            "readings": {
                                "edges": [
                                    {
                                        "node": {
                                            "valueCubicMetres": "22.000",
                                            "readingDate": "2025-08-18",
                                            "source": "CUSTOMER"
                                        }
                                    },
                                    {
                                        "node": {
                                            "valueCubicMetres": "7.000",
                                            "readingDate": "2025-04-07",
                                            "source": "OPS"
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            ]
        }
    }
}

The authentication appears to be via a JWT, which - slightly excitingly - is issued by kraken.tech. This is the smart utility platform created by Octopus Energy, and sold to other utility companies, suggesting the API is going to be of a fairly high quality.

The lack of any API key is disappointing, but the auth seems very simple: another GraphQL API request of the format

{
    "query": "mutation ObtainKrakenToken($input: ObtainJSONWebTokenInput!) {
      obtainKrakenToken(input: $input) {
        token
        payload
        refreshToken
        refreshExpiresIn
      }
    }",
    "variables": {
        "input": {
            "email": "****@gmail.com",
            "password": "********"
        }
    },
    "operationName": "ObtainKrakenToken"
}

which returns

{
    "data": {
        "obtainKrakenToken": {
            "token": "***",
            "payload": {
                "sub": "kraken|account-user:****",
                "gty": "EMAIL-AND-PASSWORD",
                "email": "****@gmail.com",
                "tokenUse": "access",
                "iss": "https://api.st.kraken.tech/v1/graphql/",
                "iat": 1755517909,
                "exp": 1755518809,
                "origIat": 1755517909
            },
            "refreshToken": "****",
            "refreshExpiresIn": 1755519709
        }
    }
}

I’ll do some more research into whether the Severn Trent instance of Kraken does indeed supports API keys, and they’re just not exposing it via a UI - in my Octopus account I can see there is a GraphQL request that will create an API key for me:

{
    "query": "mutation regenerateSecretKey {
      regenerateSecretKey {
        key
        __typename
      }
    }",
    "variables": {},
    "operationName": "regenerateSecretKey"
}

…which might also work for Severn Trent… :crossed_fingers:

2 Likes