Skip to content

Instantly share code, notes, and snippets.

@BenWoodford BenWoodford/LeafAPI.md
Last active Oct 13, 2019

Embed
What would you like to do?
New Nissan Connect EV API

Late 2018 Update

I am no longer working on this as the new API is US-only as I'm in the UK, so cannot even use it or the new app. Please don't ask me questions about it as I honestly can't remember anything.

Nissan Connect EV 2018 API

This is a work in progress, just jotting down my findings from the APK decompile so far. As I can only read the decompiled Java and not MITM the app due it not working in the UK, getting the payload info may take a while. There's loads of API calls so this may not be thorough for a while.

Base URL: https://icm.infinitiusa.com/NissanLeafProd/rest

Battery

GET /battery/vehicles/:vin/getChargingStatusRequest

POST /battery/vehicles/:vin/remoteChargingRequest

POST /battery/vehicles/:vin/cancelRemoteChargingRequest

HVAC

POST /hvac/vehicles/:vin/activateHVAC

POST /hvacSchedule/vehicles/:vin/cancelHVACSchedule

POST /hvacSchedule/vehicles/:vin/createHVACSchedule

POST /hvac/vehicles/:vin/deactivateHVAC

GET /hvacSchedule/vehicles/:vin/getHvacSchedule

POST /hvacSchedule/vehicles/:vin/updateHVACSchedule

Find My Car

POST /vehicleLocator/vehicles/:vin/refreshVehicleLocator

POST /vehicleLocator/vehicles/:vin/getNotificationHistory

Security

POST /remote/vehicles/:vin/accounts/:accountId/rdl/createRDL

POST /remote/vehicles/:vin/accounts/:accountId/rdl/createRUDL

Horn and Lights

POST /remote/vehicles/:vin/accounts:accountId/rhl/createRHL

Misc

GET /remote/securityQuestions

PUT /remote/vehicles/:vin/accounts/:accountId/authorizationInformation

Account Stuff

POST /auth/softLoginforAAS

Can take a query string of ?vin=<vinHere>&subscription=<true/false>

POST Body:

{
	"userid": <username>,
    "password": <password>,
    "country": "US", // Others to come?
    "brand-s": "N", // N for Nissan?
    "language-s": "en"
}

@sewi-cpan

This comment has been minimized.

Copy link

sewi-cpan commented Apr 24, 2018

curl -d @t.json -vvv 'https://icm.infinitiusa.com/NissanLeafProd/rest/auth/softLoginforAAS' replies:

HTTP/1.1 401 Unauthorized

<title>JBoss Web/7.4.10.Final-redhat-1 - JBWEB000064: Error report</title>[...]

JBWEB000065: HTTP Status 401 - Invalid API Key


JBWEB000309: type JBWEB000067: Status report

JBWEB000068: message Invalid API Key

JBWEB000069: description JBWEB000121: This request requires HTTP authentication.

Looks like some HTTP Basic Auth data is missing.

MITM won't work as the URL is HTTPS.

@matt

This comment has been minimized.

Copy link

matt commented May 9, 2018

I purchased a used 2015 leaf last week and it was delivered today! I am excited to begin working on an [iOS] app to interface with the vehicle. Thank you for beginning the effort with the new API.

I began looking into the authorization request. It's very straight forward:

POST https://icm.infinitiusa.com/NissanLeafProd/rest/auth/authenticationForAAS

Headers

Content-Type: application/json; charset=utf-8
API-Key: f950a00e-73a5-11e7-8cf7-a6006ad3dba0

Body

{
  "authenticate": {
    "userid": "first.last@example.com",
    "brand-s": "N",
    "language-s": "en_US",
    "password": "ILoveMyLeaf!",
    "country": "US"
  }
}

200 OK

{
  "vehicles": [
    {
      "uvi": "xxxxxxxxxxxxxxxxx",
      "brands": "N",
      "modelcode": "xxxxx",
      "modelname": "LEAF",
      "modelyear": "2015",
      "extcolor": "",
      "nickname": "LEAF",
      "pinAndPassword": null,
      "batteryRecords": {
        "operationResult": "START",
        "lastUpdatedDateAndTime": "2018-01-01T11:22:33Z",
        "batteryStatus": {
          "batteryChargingStatus": "NO",
          "batteryCapacity": 100,
          "batteryRemainingAmount": 90,
          "soc": null
        },
        "pluginState": "NOT_CONNECTED",
        "cruisingRangeAcOn": 012345,
        "cruisingRangeAcOff": 123456,
        "timeRequired": {
        "hourRequiredToFull": 2,
        "minutesRequiredToFull": 30
      },
      "timeRequired200": {
        "hourRequiredToFull": 1,
        "minutesRequiredToFull": 30
      },
      "timeRequired200_6kW": {
        "hourRequiredToFull": 1,
        "minutesRequiredToFull": 30
      },
      "notificationDateAndTime": null
    },
    "interiorTempRecords": null,
    "subcriptionList": null,
    "genType": null,
    "deviceId": null,
    "svlStatus": null,
    "accountId": null,
    "contactId": null,
    "subscriberType": null,
    "subscriptionId": null,
    "firstName": null,
    "lastName": null,
    "rdlRequestId": null,
    "rdulRequestId": null,
    "accountStatus": null,
    "productSpecificationCode": null,
    "remoteStartReqId": null,
    "remoteStopReqId": null,
    "enrollmentCompleted": false
    }
  ],
  "authenticationInfo": {
    "pinConfigured": false,
    "securityQuestions": null
  },
  "displayMessage": null,
  "displayNoTemperatureMessage": null,
  "accountID": "niscust:nis:xxxxxxxxx",
  "authToken": "xxxxx..."
}

Things to note:

  1. The auth request returns a Cookie header. This needs to be sent with follow-up requests.
  2. API key may [or may not] be specific to the iOS app, but this shouldn't matter aside from skewing analytics.
  3. One of the employees/contractors indeed published a typo (subcriptionList) and it was deployed to production. Either QE/QA doesn't exist, or someone should be reprimanded.

I plan to continue playing around with the API. Let me know if there's anything I can help with. My limitations are access to a 2015 Nissan Leaf. Thanks!

@matt

This comment has been minimized.

Copy link

matt commented May 11, 2018

Additional endpoints:

POST /electricusage/vehicles/:vin/detailpriceSimulatordata
POST /ecoDrive/vehicles/:vin/driveHistoryRecords
POST /ecoDrive/vehicles/:vin/driveAnalysisBasicRecords
POST /ecoDrive/vehicles/:vin/driveAnalysisDetail
POST /eco/vehicles/:vin/nationalRankingBasicScreenChampionData
POST /eco/vehicles/:vin/detailNationalRankingData
POST /worldEco/vehicles/:vin/worldEcoForestBasicScreenData
POST /worldEco/vehicles/:vin/worldEcoForestAllInfo
GET /auth/getUserProfile
POST /enrollment/getpinandpassword/language/:lang

@gtlambert

This comment has been minimized.

Copy link

gtlambert commented May 21, 2018

Matt - do you know if it is possible to connect to this API using UK Nissan Leaf credentials?

@jeremyakers

This comment has been minimized.

Copy link

jeremyakers commented May 29, 2018

@matt - What tool did you use to intercept that request? The new NissanConnectEV app doesn't appear to honor proxy settings on Android, so I'm not able to intercept traffic using mitmproxy anymore.

@iceydee

This comment has been minimized.

Copy link

iceydee commented May 31, 2018

@jeremyakers I believe they're SSL-pinning, if that's the case that'll be why your mitmproxy isn't working. I have no evidence, it's just a guess from what I saw in my own experiments.

@jeremyakers

This comment has been minimized.

Copy link

jeremyakers commented May 31, 2018

@iceydee So I've been researching this and that's what I initially thought but: Actually they (Nissan) are not SSL pinning. It's actually much worse: Google is the one doing it. Android 8.x and up no longer allows apps to "trust" User Installed Certificates by default. Apps can be re-written to"opt in" but what are the chances any app is going to do that?

I pulled out an older tablet and mitmproxy is working fine on the NissanConnect EV app on Android 6.0. Sounds like iOS should also be fine as based on my research only Google/Android decided to take this drastic step to keep users from sniffing the data their device is sending back to the mothership about them.

@jeremyakers

This comment has been minimized.

Copy link

jeremyakers commented May 31, 2018

So now that I have mitmworking on my older tablet: I'm seeing a very odd behavior. The new API is refusing to give me updated battery status. It was working fine in the old API but I'm now realizing it doesn't even work in the app. When I press refresh this is what it sends to Nissan's API:

GET https://icm.infinitiusa.com/NissanLeafProd/rest/battery/vehicles/1N4BZ0CPXGC304460/getChargingStatusRequest
                        ← 200 text/plain [no content] 9.94s
Content-Type:     application/json                                                                                                                                                                                
Authorization:    <Auth-Key>
API-Key:          b6623f3c-73a5-11e7-8cf7-a6006ad3dba0                                                                                                                                                            
User-Agent:       Dalvik/2.1.0 (Linux; U; Android 6.0; Aquaris M10 FHD Build/MRA58K)                                                                                                                              
host:             icm.infinitiusa.com                                                                                                                                                                             
Connection:       Keep-Alive                                                                                                                                                                                      
Accept-Encoding:  gzip                                                                                                                                                                                            
Cookie:           JSESSIONID=<session cookie>

And the response is No Content:

Date:                           Thu, 31 May 2018 14:22:16 GMT                                                                                                                                                     
Cache-Control:                  no-cache, no-store, max-age=0, must-revalidate                                                                                                                                    
Pragma:                         no-cache                                                                                                                                                                          
Expires:                        0                                                                                                                                                                                 
X-XSS-Protection:               1; mode=block                                                                                                                                                                     
X-Frame-Options:                DENY                                                                                                                                                                              
X-Content-Type-Options:         nosniff                                                                                                                                                                           
Access-Control-Allow-Credentia  true                                                                                                                                                                              
ls:                                                                                                                                                                                                               
content-length:                 0                                                                                                                                                                                 
Connection:                     close                                                                                                                                                                             
Content-Type:                   text/plain; charset=UTF-8                                                                                                                                                         
No content

This is specifically what I captured from the app itself. And I cannot get the app to load refreshed battery data. Everything else in the app works, I can activate and cancel the HVAC, see driving/electricity records, etc. Everything works but battery status.

Does anyone have any idea why the new API would be failing to update the battery status? I also checked on the Nissan Owners Portal and battery status is refreshing fine there.

@jeremyakers

This comment has been minimized.

Copy link

jeremyakers commented May 31, 2018

Here's the JSON response from authenticateForAAS when I first sign into the app:

{
    "accountID": "niscust:nis:<AccountID>", 
    "authToken": "<AuthToken>", 
    "authenticationInfo": {
        "pinConfigured": false, 
        "securityQuestions": null
    }, 
    "displayMessage": "BatteryStatusRecords not available for the user",
    "displayNoTemperatureMessage": "InteriorTemperature Records are  not available for the VIN", 
    "vehicles": [
        {
            "accountId": null, 
            "accountStatus": null, 
            "batteryRecords": null, 
            "brands": "N", 
            "contactId": null, 
            "deviceId": null, 
            "enrollmentCompleted": true, 
            "extcolor": "PEARL WHITE", 
            "firstName": null, 
            "genType": null, 
            "interiorTempRecords": null, 
            "lastName": null, 
            "modelcode": "17216", 
            "modelname": "LEAF", 
            "modelyear": "2016", 
            "nickname": "2016 Leaf", 
            "pinAndPassword": null, 
            "productSpecificationCode": null, 
            "rdlRequestId": null, 
            "rdulRequestId": null, 
            "remoteStartReqId": null, 
            "remoteStopReqId": null, 
            "subcriptionList": null, 
            "subscriberType": null, 
            "subscriptionId": null, 
            "svlStatus": null, 
            "uvi": "<MyVIN>"
        }
    ]
}

Notice the "DisplayMessage"?

"displayMessage": "BatteryStatusRecords not available for the user",

This doesn't actually get displayed anywhere in the App that I can see...

@matt

This comment has been minimized.

Copy link

matt commented Jun 6, 2018

Apologies for stepping away from this conversation briefly.

@gtlambert I live in the US and have not tested whether other regional credentials are compatible with this API.

@jeremyakers I used Charles Proxy to sniff the traffic on iOS. The app is not using ssl-pinning.

@matt

This comment has been minimized.

Copy link

matt commented Jun 6, 2018

@jeremyakers I have also noticed intermittent hiccups when retrieving battery records. I haven't had a chance to dig in, but have noticed the app not refreshing battery percentage and/or range appropriately.

@FrancoSabadini

This comment has been minimized.

Copy link

FrancoSabadini commented Aug 29, 2018

@BenWoodford are these APIs still not working in the UK?

@FrancoSabadini

This comment has been minimized.

Copy link

FrancoSabadini commented Aug 29, 2018

Hey @matt, when trying to authenticate with this API I'm getting this error:

{
    "errorMessage": "Authentication Failure",
    "errorCode": 910
}

Do you have any idea why that can be?

@paultanner

This comment has been minimized.

Copy link

paultanner commented Sep 11, 2018

Thx for your working in putting this together.
FYI. I tried /auth/softLoginforAAS in the UK with my You+Nissan account credentials.
I have a 2018 LEAF and the app works OK with these creds (set up a couple of months ago)
Got back a 401 with "Invalid API key" which is odd because I was hoping to get an API key back.
Maybe they have not yet enabled this here?

@colleenfeng

This comment has been minimized.

Copy link

colleenfeng commented Sep 14, 2018

I tried to authenticate my Canadian account using the API key and stuff posted above, and got a 401 back with invalid API key as well. Anyone know if it works for Canada?

@brianflex

This comment has been minimized.

Copy link

brianflex commented Sep 17, 2018

The V2 API's use a different set of country codes than the previous V1 API's. But, it's not clear to me what's supported. Colleen, try changing this line:
"country": "US"
Maybe you can put in CA or CN or CD and it would work? If you find a solution, please share.

@sirfergy

This comment has been minimized.

Copy link

sirfergy commented Oct 9, 2018

Anyone able to figure out if the AC is on or off? I want to integrate with HomeKit but not being able to get the status will make things less than ideal. From the app it doesn't appear to be possible to get either.

@mckooper

This comment has been minimized.

Copy link

mckooper commented Oct 14, 2018

@sirfergy - I haven't seen anything yet that lets you query the state of the HVAC, or the state of the door locks for that matter. It's as if the API was written by someone right out of school whose intentions were good, but they had no experience with what they were doing.

I've just started playing around with this and my 2018 Leaf - I'll follow up with a few POST body definitions...

@mckooper

This comment has been minimized.

Copy link

mckooper commented Oct 14, 2018

POST /hvac/vehicles/:vin/deactivateHVAC

Headers

  Content-Type:  application/json; charset=utf-8
  API-Key:       f950a00e-73a5-11e7-8cf7-a6006ad3dba0
  Authorization: <authToken>
  Cookie:        <Set-Cookie>

Body


(empty string)

200 OK

{
    "messageDeliveryStatus": "Success"
}

Notes

"messageDeliveryStatus : Success" - so the message was successfully delivered, but technically we still don't know anything about the state of the HVAC. Lovely.

@mckooper

This comment has been minimized.

Copy link

mckooper commented Oct 14, 2018

POST /hvac/vehicles/:vin/activateHVAC

Headers

  Content-Type:  application/json; charset=utf-8
  API-Key:       f950a00e-73a5-11e7-8cf7-a6006ad3dba0
  Authorization: <authToken>
  Cookie:        <Set-Cookie>

Body

{
  "executionTime" : "2018-10-14T21:08:00Z"
}

or

{
  "preACunit" : "F",
  "executionTime" : "2018-10-14T05:49:53Z",
  "preACtemp" : "72"
}

200 OK

{
    "messageDeliveryStatus": "Success"
}

Notes

  • Again, the response doesn't actually tell us that the HVAC is now active.
  • I don't know if the value of "executionTime" matters
  • I suppose "preACunit" could also be "C", but I haven't tried it (don't want to set my car on fire because my feeble US brain can't handle the Metric system)
@dernotte

This comment has been minimized.

Copy link

dernotte commented Oct 21, 2018

I am curious to know where you get the URL and different endpoint from. Is there an official documentation about Nissan API.
I have a Nissan Leaf 2014 and I am currently using this base URL : https://gdcportalgw.its-mo.com/api_v180117_NE/gdc/, not the https://icm.infinitiusa.com/NissanLeafProd/rest. I am very interested finding an endpoint to stop charging. I saw the infinitiusa.com has the endpoint, but it does not work for me. Is it something that works on the 2018/2019 and not on the 2014 ? The getChargingStatusRequest endpoint works fine for me.

@mckooper

This comment has been minimized.

Copy link

mckooper commented Oct 23, 2018

@dernotte - The infinitiusa URL is what my iPhone app is using, and it would not surprise me if that was specific to both the US and 2018 model years.

@Raiden38

This comment has been minimized.

Copy link

Raiden38 commented Feb 6, 2019

Did you find the way to make de remote door lock work?

I used the path above /remote/vehicles/:vin/accounts/:accountId/rdl/createRDL, I get a status 200 but it does not work. I also tried adding parameters Command, Lock and Delay like the nissan website but no success.

@jfarinhote

This comment has been minimized.

Copy link

jfarinhote commented Feb 11, 2019

Any news on this thread? I am not sure what is the API-key and the credentials json body to send. I am trying to make a simple authentication for starting

@Tobiaswk

This comment has been minimized.

Copy link

Tobiaswk commented Jun 17, 2019

Hello I'm the developer of the My Leaf app on Android and iOS. It seems the NissanConnect EV app for US users is beginning to use this new API. I want to implement support for the new US-based API. I'm stuck though because I do not have an API Key.

@jfarinhote I'm in the same boat. @matt where did you get your API-Key?

@matt

This comment has been minimized.

Copy link

matt commented Jun 17, 2019

@jfarinhote, @Tobiaswk

A sample authentication request is available near the beginning of this thread. The original request was performed over a year ago, but the API-Key was valid on May 8, 2018. I used Charles Proxy to sniff the traffic from the iOS Nissan Connect EV application.

@Tobiaswk

This comment has been minimized.

Copy link

Tobiaswk commented Jun 20, 2019

@matt Sorry. I did not notice that. Thanks for the information! The API-Key still works!

On another note has anyone gotten anything succesful from these calls;
POST /electricusage/vehicles/:vin/detailpriceSimulatordata
POST /ecoDrive/vehicles/:vin/driveHistoryRecords
POST /ecoDrive/vehicles/:vin/driveAnalysisBasicRecords
POST /ecoDrive/vehicles/:vin/driveAnalysisDetail

For everyone one of these the request goes through with HTTP 200. Nothing other than error messages or empty values are returned though.
Examples;
{"errorMessage":"An error occurred while retrieving price simulator information.","errorCode":934}

{"errorMessage":"An error occurred while retrieving Car Karte Detail Info","errorCode":977}

{"dateSummary":{"targetDate":"2019-06-20","electricMileage":null,"electricMileageLevel":null,"powerConsumptMoter":null,"powerConsumptMoterLevel":null,"powerConsumpt$ inus":null,"powerConsumptMinusLevel":null,"powerConsumptAUX":null,"powerConsumptAUXLevel":null},"electricCostScale":"miles/kWh"}}

@mrtaormina

This comment has been minimized.

Copy link

mrtaormina commented Jul 9, 2019

I was able to get the price simulator data successfully.

POST /electricusage/vehicles/:vin/detailpriceSimulatordata

BODY:
{
"Targetmonth": ""
}

RESPONSE:
{'priceSimulatorDetailInfoResponsePersonalData': {'targetMonth': '201906', 'totalPowerConsumptTotal': '157861.86', 'totalPowerConsumptMoter': '213934.26', 'totalPowerConsumptMinus': '56072.4', 'electricPrice': '0.11', 'electricBill': '17.3648046', 'electricCostScale': 'miles/kWh', 'mainRateFlg': 'USER', 'existFlg': 'EXIST', 'priceSimulatorTotalInfo': {'totalNumberOfTrips': '106', 'totalPowerConsumptTotal': '157861.86', 'totalPowerConsumptMoter': '213934.26', 'totalPowerConsumptMinus': '56072.4', 'totalTravelDistance': '1276707', 'totalElectricMileage': '5.0', 'totalCO2Reductiont': '232'}, 'priceSimulatorDetailInfoDateList': {'priceSimulatorDetailInfoDate': [{'priceSimulatorDetailInfoTripList': {'priceSimulatorDetailInfoTrip': [{'tripId': '1', 'powerConsumptTotal': '491.14', 'powerConsumptMoter': '709.34', 'powerConsumptMinus': '218.2', 'travelDistance': '4700', 'electricMileage': '5.9', 'cO2Reduction': '1', 'mapDisplayFlg': 'ACTIVE', 'gpsDatetime': '2019-06-01T18:02:19'}, {'tripId': '2'..........}

@Tobiaswk

This comment has been minimized.

Copy link

Tobiaswk commented Jul 9, 2019

Thanks for writing! I've created a Dart client library for this new North American API. It supports most of the features the API offers but not all yet; https://github.com/Tobiaswk/dartnissanconnectna
I suppose someone can use it as a reference.

@zandzpider

This comment has been minimized.

Copy link

zandzpider commented Jul 29, 2019

as of late, i can't connect to the europe api anymore or sniff any traffic from my android app (that's how i reverse engineered the api to begin with).

example on battery request url is:
https://gdcportalgw.its-mo.com/gworchest_160803EC/gdc/BatteryStatusRecordsRequest.php

anyone got any ideas on whats going on ?

Thanks

@jfarinhote

This comment has been minimized.

Copy link

jfarinhote commented Jul 29, 2019

GPS is not working with the latest api

@arussell

This comment has been minimized.

Copy link

arussell commented Jul 31, 2019

The Europe API endpoints have definitely changed, and it seems to be related to the "previous versions will stop working on 2019-07-29" message displayed in the app:

apichange

My guess is that the gworchest_160803EC part is now different, perhaps using a different datecode. It's still connecting to the same hostname but it's bypassing proxy config on Android, and outright failing when proxied on iOS, so I'm having trouble getting mitmproxy to intercept it. It might need mitmproxy running in transparent proxy mode, with the data being grabbed from an older Android device in order to get the proper URLs, assuming SSL pinning isn't happening (although SSL pinning would explain the errors it threw on iOS when other traffic was working through the proxy).

@Tobiaswk

This comment has been minimized.

Copy link

Tobiaswk commented Jul 31, 2019

Hey guys,
There is indeed a new version of the Nissan Carwings API. And GPS is not working with the new version.
Here are the details I have recorded; https://gitlab.com/tobiaswkjeldsen/dartcarwings/issues/15

This discussion is about the North American NissanConnect API. Maybe we should find another place for discussing the old API?

@zandzpider

This comment has been minimized.

Copy link

zandzpider commented Jul 31, 2019

@Tobiaswk thank you so much!
Implemented the changes in my c# nissan http service.
Thinking of releasing it as a package if anyone is interested.

@arussell

This comment has been minimized.

Copy link

arussell commented Jul 31, 2019

Thanks @Tobiaswk!

@howartp84

This comment has been minimized.

Copy link

howartp84 commented Jul 31, 2019

Do we know if the North American (infinityusa.com) API is the one that the new UK 2019 cars are using, aka the "NissanConnect Services" app rather than the "NissanConnect EV" app that <2019 cars use?

Or, has anyone done any digging on the new UK 2019 API?

@howartp84

This comment has been minimized.

Copy link

howartp84 commented Aug 3, 2019

To answer my own question, the answer is no.

North America uses the infinityusa.com API.

New UK 2019 cars (NissanConnect Services) use kamereon.org / kamereon.io

See https://gitlab.com/tobiaswkjeldsen/dartcarwings/issues/13 for Tobias's progress on both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.