timdorr / tesla-api

🚘 A Ruby gem and unofficial documentation of Tesla's JSON API for the Model S, 3, X, and Y.
https://tesla-api.timdorr.com/
MIT License
1.99k stars 532 forks source link

Invoices #539

Open wannesdemaeght opened 2 years ago

wannesdemaeght commented 2 years ago

in the endpoints file there is some documentation about invoices. I would like to automatically download my supercharging invoices, but can not get it to work.

"DOWNLOAD_CHARGING_INVOICE": {
    "TYPE": "GET",
    "URI": "bff/v2/mobile-app/charging/invoice/{uuid}",
    "AUTH": true
  },
  "DOWNLOAD_CHARGING_SUBSCRIPTION_INVOICE": {
    "TYPE": "GET",
    "URI": "bff/v2/mobile-app/charging/subscription/invoice/{invoiceId}",
    "AUTH": true
  },

using these endpoints needs a uuid or invoiceId, which I am trying to obtain with this endpoint:

  "MANAGE_GET_SUBSCRIPTION_INVOICES": {
    "TYPE": "GET",
    "URI": "bff/v2/mobile-app/subscriptions/invoices",
    "AUTH": true
  },

I am using this url: https://owner-api.teslamotors.com/bff/v2/mobile-app/subscriptions/invoices

I am using GET, with requestheader application/json params is: {"vehicle_id":"xxxxxxxxxxxx"} (id is correct, and works for all other api requests)

response is: {"response":null,"error":"param is missing or the value is empty: vehicle_id","error_description":""}

I tried attaching the vehicle_id in the url, as needs to be done for other calls, but then I get a 404 error. Any help?

jamesdeck commented 2 years ago

Curious about this too. I've tried for days to get supercharging costs from the API but have not gotten anywhere.

idriskhenchil commented 2 years ago

What headers are you sending?

timdorr commented 2 years ago

The BFF (backend-for-frontend) endpoints don't appear to authenticate the same way as the other vehicle endpoints do. I'd love to figure out what's going on here. Since they started obfuscating the JavaScript bundle in the app, it's gotten a little more difficult to figure out what the app is up to with these endpoints. I either need to packet sniff or just de-obfuscate the JS bundle, but we should probably focus a bit on figuring out how to call these endpoints.

idriskhenchil commented 2 years ago

The BFF (backend-for-frontend) endpoints don't appear to authenticate the same way as the other vehicle endpoints do. I'd love to figure out what's going on here. Since they started obfuscating the JavaScript bundle in the app, it's gotten a little more difficult to figure out what the app is up to with these endpoints. I either need to packet sniff or just de-obfuscate the JS bundle, but we should probably focus a bit on figuring out how to call these endpoints.

I've been able to packet sniff the app and I'll post that information here when I get a chance. Currently trying to packet sniff the actual car as well, but that's proving to be a little tricky so far.

idriskhenchil commented 2 years ago

Through checking the HTTP requests on the app, I've been able to get Invoice data through:

POST https://ownership.tesla.com/graphql?deviceLanguage=en&deviceCountry=US&vin={vin}&operationName=getChargingHistoryV2

The request is as follows:

POST /graphql?deviceLanguage=en&deviceCountry=US&vin={VIN}&operationName=getChargingHistoryV2 HTTP/1.1
Host: ownership.tesla.com
Accept: */*
Authorization: Bearer {token}
Accept-Encoding: gzip, deflate, br
Accept-Language: en
Cache-Control: no-cache
charset: utf-8
Content-Length: 1376
User-Agent: Tesla/1032 CFNetwork/1331.0.7 Darwin/21.4.0
Connection: keep-alive
x-tesla-user-agent: TeslaApp/4.8.1/5e1bfb8d0d/ios/15.4.1
Content-Type: application/json
x-txid: {x-txid}
Cookie: bm_sv={value}; ak_bmsc={value}

Which in turn will return roughly the following response

"charging": {
        "historyV2": {
          "data": [{
            "countryCode": "US",
            "programType": "PTSCH",
            "billingType": "IMMEDIATE",
            "vin": "{VIN}",
            "credit": null,
            "invoices": null,
            "chargeSessionId": "1234565-0-12345566",
            "siteLocationName": "LOCATION",
            "chargeStartDateTime": "2022-05-21T21:06:18-04:00",
            "chargeStopDateTime": "2022-05-21T21:46:20-04:00",
            "unlatchDateTime": "2022-05-21T21:46:21-04:00",
            "fees": [{
              "sessionFeeId": 1234566,
              "feeType": "CHARGING",
              "payorUid": null,
              "amountDue": null,
              "currencyCode": "USD",
              "pricingType": "PAYMENT",
              "usageBase": 61,
              "usageTier1": 10,
              "usageTier2": 12,
              "usageTier3": 17,
              "usageTier4": 0,
              "rateBase": 0.17,
              "rateTier1": 0,
              "rateTier2": 0,
              "rateTier3": null,
              "rateTier4": null,
              "totalTier1": 0,
              "totalTier2": 0,
              "totalTier3": 0,
              "totalTier4": 0,
              "uom": "kwh",
              "isPaid": true,
              "uid": 1234567,
              "totalBase": 10.37,
              "totalDue": 10.37,
              "netDue": 10.37,
              "status": "PAID"
            }],
            "vehicleMakeType": "TESLA",
            "sessionId": 1234567,
            "surveyCompleted": null,
            "surveyType": null,
            "postId": "0",
            "cabinetId": "vehicleMakeType",
            "din": ""
          }

I've only been able to view the request on the Tesla app. I'm still trying to figure out the header situation since I believe the x-txid or the cookies are single use.

If you are trying to get the actual PDF invoice instead, you can try:

GET https://ownership.tesla.com/mobile-app/charging/invoice/{INVOICE_ID}?deviceCountry=US&deviceLanguage=en&vin={VIN}

Which takes the same headers as above.

I do get a 401 when trying to make the request through a REST client, which I think may be related to this

wannesdemaeght commented 2 years ago

Any update on this? As there is no way to get my invoices (premium connectivity and supercharging) via mail, I’d like to access them via api…

davidhodge commented 2 years ago

I'm also curious if you found anything here. If i were to guess, the secret is in the cookies.

idriskhenchil commented 2 years ago

PDF invoices can be accessed with

GET https://ownership.tesla.com/mobile-app/charging/invoice/{INVOICE_ID}?deviceCountry=US&deviceLanguage=en&vin={VIN}

The inconvenience is that you'd need to know the INVOICE_ID.

davidhodge commented 2 years ago

thanks @idriskhenchil, we're still a bit stuck on getting the list of invoices. Presently getting back "Bad Request". Perhaps missing some headers.

idriskhenchil commented 2 years ago

@davidhodge Also the same error I get back when trying to access the request outside of the app. I used the same headers present in the mobile request as the headers I used in the client.

My wild guess is that I think the app may generate a client-side token that is used to validate where the request is coming from, in order to prevent the request from being made elsewhere. In a sense each request would only be single-use which could be why it works once when analyzing the request in the app, and doesn't work elsewhere.

chadhurin commented 2 years ago

@idriskhenchil @wannesdemaeght I was able to get invoice history response off the app without cookies with this endpoint: POST https://akamai-apigateway-charging-ownership.tesla.com/graphql?deviceLanguage=en&deviceCountry=US&ttpLocale=en_US&vin={vin}&operationName=getChargingHistoryV2

I've seen other "akamai-apigateway-" host prefixes but I searched a while and couldn't find "akamai-apigateway-charging-ownership.tesla.com".

I did not need to add the "x-txid" key to the header (or even the bm_sv cookies).

I hope I'm on the right track and this is helping.

wannesdemaeght commented 2 years ago

hi @chadhurin unfortunately it's not working for me. responsestatus is 400 - Bad Request. accompanying text: {"errors":[{"message":"Oops! Something went wrong. 387be28a-4046-4479-9d86-61bebf6a10cf","txId":"387be28a-4046-4479-9d86-61bebf6a10cf"}]}

I used both POST and GET, with the url you provided, and a working bearer-token...

chadhurin commented 2 years ago

Hey, @wannesdemaeght Try this in your body

{ "query": "\n query getChargingHistoryV2($pageNumber: Int!, $sortBy: String, $sortOrder: SortByEnum) {\n me {\n charging {\n historyV2(pageNumber: $pageNumber, sortBy: $sortBy, sortOrder: $sortOrder) {\n data {\n ...SparkHistoryItemFragment\n }\n totalResults\n hasMoreData\n pageNumber\n }\n }\n }\n}\n \n fragment SparkHistoryItemFragment on SparkHistoryItem {\n countryCode\n programType\n billingType\n vin\n credit {\n distance\n distanceUnit\n }\n chargingPackage {\n distance\n distanceUnit\n energyApplied\n }\n invoices {\n fileName\n contentId\n invoiceType\n }\n chargeSessionId\n siteLocationName\n chargeStartDateTime\n chargeStopDateTime\n unlatchDateTime\n fees {\n ...SparkHistoryFeeFragment\n }\n vehicleMakeType\n sessionId\n surveyCompleted\n surveyType\n postId\n cabinetId\n din\n}\n \n fragment SparkHistoryFeeFragment on SparkHistoryFee {\n sessionFeeId\n feeType\n payorUid\n amountDue\n currencyCode\n pricingType\n usageBase\n usageTier1\n usageTier2\n usageTier3\n usageTier4\n rateBase\n rateTier1\n rateTier2\n rateTier3\n rateTier4\n totalTier1\n totalTier2\n totalTier3\n totalTier4\n uom\n isPaid\n uid\n totalBase\n totalDue\n netDue\n status\n}\n ", "variables": { "sortBy": "start_datetime", "sortOrder": "DESC", "pageNumber": 1 }, "operationName": "getChargingHistoryV2" }

with these headers:

--header 'User-Agent: Tesla/1195 CFNetwork/1388 Darwin/22.0.0' --header 'x-tesla-user-agent: TeslaApp/4.11.1/12ad93c62a/ios/16.0' --header 'Content-Type: application/json' --header 'Authorization: Bearer {token}

chadhurin commented 2 years ago

@wannesdemaeght Did that work?

wannesdemaeght commented 2 years ago

Hi @chadhurin, thanks for your help! I got everything working exactly as I wanted.

could you maybe help me along with the correct body to get a list of the premium connectivity invoices?

wannesdemaeght commented 2 years ago

@chadhurin do you know what endpoint I could use for the premium connectivity invoices, as well as what to put in the body? Would be a great help!

andrewdevelopz commented 1 year ago

@chadhurin Hey, do you know if it is possible to get the supercharger location's latitude and longitude from the graphql query from your comment:

https://github.com/timdorr/tesla-api/issues/539#issuecomment-1206834760

If so, can you let me know what needs to be added to that query? Thank you.

thebrrt commented 1 year ago

@idriskhenchil @wannesdemaeght I was able to get invoice history response off the app without cookies with this endpoint: POST https://akamai-apigateway-charging-ownership.tesla.com/graphql?deviceLanguage=en&deviceCountry=US&ttpLocale=en_US&vin={vin}&operationName=getChargingHistoryV2

I've seen other "akamai-apigateway-" host prefixes but I searched a while and couldn't find "akamai-apigateway-charging-ownership.tesla.com".

I did not need to add the "x-txid" key to the header (or even the bm_sv cookies).

I hope I'm on the right track and this is helping.

So this is still working in 2023, but I noticed it no longer returns the invoices for each VIN. It'll instead send a list of the most recent invoices regardless of VIN, but you still need to provide a VIN query parameter or it'll return an error 400.

Is that your experience or am I sending my request incorrectly?

I also noticed invoice.invoices.contentId is null for some invoices. Does this just mean a PDF isn't available to download yet?

slavikme commented 1 year ago

I wonder, what is the query that feeds the graph located in the Charge Stats section in the app? image

I want to create a periodic charging report (monthly), to include data such as “charge start time”, “charge end time”, “energy consumed”, “location” (home, supercharge, work, other) and the cost, for each vehicle.

Sadly, Tesla do not provide charging data export, so I wonder if it’s possible to retrieve it using the GraphQL query or the REST API? Because, all the data I need does exist in the app.

Thanks!

P.S: I am JS developer. I would appreciate if someone can send me the obfuscated JS files from the app. I want to try to read them in order to extract as much information as possible.

superfloh247 commented 1 year ago

getChargingHistoryV2 and GetNearbyChargingSites return http 403 since approx 24h

does it still work for you?

andrewdevelopz commented 1 year ago

@superfloh247 I was getting the same error for getChargingHistoryV2, so I found the invoices from this uri.

https://ownership.tesla.com/mobile-app/charging/history?

Query Params:
vin=%
deviceLanguage=en
deviceCountry=US

Headers:
Authorization: Bearer %

It only returns the 5 most recent invoices and I am not sure how to query for more pages. Would you or anyone else know how?

thebrrt commented 1 year ago

getChargingHistoryV2 and GetNearbyChargingSites return http 403 since approx 24h

does it still work for you?

Just checked and I too am getting error 403 now ://

thebrrt commented 1 year ago

@superfloh247 I was getting the same error for getChargingHistoryV2, so I found the invoices from this uri.

https://ownership.tesla.com/mobile-app/charging/history?

Query Params:
vin=%
deviceLanguage=en
deviceCountry=US

Headers:
Authorization: Bearer %

It only returns the 5 most recent invoices and I am not sure how to query for more pages. Would you or anyone else know how?

Thank you for the solution! I implemented it and I got ALL of my invoices since late November of 2022

andrewdevelopz commented 1 year ago

@superfloh247 I was getting the same error for getChargingHistoryV2, so I found the invoices from this uri.

https://ownership.tesla.com/mobile-app/charging/history?

Query Params:
vin=%
deviceLanguage=en
deviceCountry=US

Headers:
Authorization: Bearer %

It only returns the 5 most recent invoices and I am not sure how to query for more pages. Would you or anyone else know how?

Thank you for the solution! I implemented it and I got ALL of my invoices since late November of 2022

No problem. Did you add any extra query params?

thebrrt commented 1 year ago

@superfloh247 I was getting the same error for getChargingHistoryV2, so I found the invoices from this uri.

https://ownership.tesla.com/mobile-app/charging/history?

Query Params:
vin=%
deviceLanguage=en
deviceCountry=US

Headers:
Authorization: Bearer %

It only returns the 5 most recent invoices and I am not sure how to query for more pages. Would you or anyone else know how?

Thank you for the solution! I implemented it and I got ALL of my invoices since late November of 2022

No problem. Did you add any extra query params?

No, this is how I make the request:

image
superfloh247 commented 1 year ago

No, this is how I make the request: image

works for me, but it's incomplete

https://akamai-apigateway-charging-ownership.tesla.com/graphql?deviceLanguage=en&deviceCountry=US&ttpLocale=en_US&vin=" + car.Vin + "&operationName=getChargingHistoryV2" was paginated and I could poll all supercharger sessions since 2019

the App also loads paginated, I'll play around with URL params :)

stevemer commented 1 year ago

What'd you find? @superfloh247

superfloh247 commented 1 year ago

It was a combination of HTTP headers to make it work again

https://github.com/superfloh247/TeslaLogger/commit/f403495c95f76761d3a1c18aeae930dc29498f3a

superfloh247 commented 1 year ago

and by "it works" I mean the GraphQL queries, not the GET request

wannesdemaeght commented 1 year ago

this endpoint works, and is a lot cleaner to implement. Too bad that there are only 5 invoices generated...

Anyone have an idea on how to get the premium connectivity invoices? I tried url https://ownership.tesla.com/mobile-app/premium-connectivity/history?vin=5YJ3E7EB9KF48520&deviceLanguage=en&deviceCountry=US but no dice... (VIN spoofed).

slavikme commented 1 year ago

I wonder, what is the query that feeds the graph located in the Charge Stats section in the app? image

I want to create a periodic charging report (monthly), to include data such as “charge start time”, “charge end time”, “energy consumed”, “location” (home, supercharge, work, other) and the cost, for each vehicle.

Sadly, Tesla do not provide charging data export, so I wonder if it’s possible to retrieve it using the GraphQL query or the REST API? Because, all the data I need does exist in the app.

Thanks!

P.S: I am JS developer. I would appreciate if someone can send me the obfuscated JS files from the app. I want to try to read them in order to extract as much information as possible.

Found the request! :)

Request

POST https://owner-api.teslamotors.com/api/1/vehicles/{{vehicle-id}}/charge_history?interval={{interval}}&currency_code=ILS&client_country=IL&time_zone=Indian/Mayotte&start_date={{start-date}}&end_date={{end-date}}`

Headers

Authorization: Bearer {{token}}
Content-Type: application/json
x-tesla-user-agent: TeslaApp/4.24.0-1911

[!IMPORTANT] x-tesla-user-agent header is important!

Body

You can leave it empty.

Variables

{{vehicle-id}}

Your vehicle ID, that can be retrieved using the https://owner-api.teslamotors.com/api/1/vehicles request.

{{interval}}

Optional. The interval of the records. As far as I know, it supports only the values day and month. If no interval param is provided, day is the default.

{{start-date}}

Optional. The start date from which to show the records.
It should look like this: 2023-07-01T00%3A00%3A00%2B03%3A00.
If start_time is omitted, will return the recent records.

[!IMPORTANT] Make sure value is URL encoded.

[!NOTE] The resolution of each record, depends on the {{interval}} value.

{{end_date}}

Required if start_date is provided. The start date from which to show the records.
It should look like this: 2023-07-31T00%3A00%3A00%2B03%3A00.

[!IMPORTANT] Make sure the value is URL encoded.

{{token}}

You know. Your token in Tesla, generated by OAuth 2.0 protocol.

aSauerwein commented 3 months ago

this endpoint works, and is a lot cleaner to implement. Too bad that there are only 5 invoices generated...

Anyone have an idea on how to get the premium connectivity invoices? I tried url https://ownership.tesla.com/mobile-app/premium-connectivity/history?vin=5YJ3E7EB9KF48520&deviceLanguage=en&deviceCountry=US but no dice... (VIN spoofed).

hi @wannesdemaeght i know it has been a long time, but this week I figured out the correct endpoint for Premium Connectivity. It seems like that we also have the same use case "invoices per mail" https://github.com/aSauerwein/tesla-invoices/blob/main/download_v2.py

this is what you need for Premium Connectivity Invoices

hope this helps anyone