Crafting Bytes for Better Lives

Working with the Tesla API

Published on July 7, 2016

Working with the Tesla API

I finally decided to address the Tesla API and work on a project that includes talking to the API. This means of course that I have to take a closer look at how it works and how I can actually make it work with my own code. There are a few wonderful GitHub libraries that you can implement in your own application and a very thorough documentation on the Tesla API, which could be found at docs.timdorr.apiary.io (the Apiary service has since been shut down). But nonetheless, this all didn’t quite work for me. I’m coding with Swift 2.x in a command line based application, as I’m going to make the shift to a fully server-based application in the long run.

Getting Started with the Tesla API

The basics that need to be understood when coding with the Tesla API is the underlying protocol, or at least which protocol it tries to follow. In this case we are closely related to the OAuth 2.0 protocol. You initiate your API connection by requesting an access token (bearer token) by throwing a POST request at the server with quite some content in it. So, what is really required to make it work?

  • grant_type: password
  • client_id: can be found in a link on the apiary docs page
  • client_secret: can be found in a link on the apiary docs page
  • email: your personal email address used for the Tesla account
  • password: your holy grail of passwords, as this grants access to the vehicle, if enabled

The above listed elements are required to be put into the HTTP body of the request in JSON format. But you also have to pay attention to your header variables. Luckily, there is only one thing you need to set:

  • Content-Type: application/json; charset=utf-8

Now go ahead and throw this request at the Tesla API server address https://owner-api.teslamotors.com/oauth/token and read the access_token from the response. It will look like this:

{
  "access_token": "e5f...e1d",
  "token_type": "bearer",
  "expires_in": 7776000,
  "created_at": 1467907225
}

In the next step you are going to need to request a list of vehicles that are registered under your account. This is going to be straightforward. Throw a GET request at the correct web address from Tesla, https://owner-api.teslamotors.com/api/1/vehicles, but be aware that you need to add your access_token to the headers of the request. You can do that just like you did above with the Content-Type (not needed now!), but now as follows:

  • Authorization: Bearer e5f…e1d

This in result will grant you a response such as this one:

{
  "response": [
    {
      "id": 1132...3230,
      "vehicle_id": 58...60,
      "vin": "5YJ...259",
      "display_name": "Hurricane",
      "option_codes": "REEU,AD04,X003",
      "color": null,
      "tokens": ["2903...4468", "c13f...9968"],
      "state": "online",
      "id_s": "1132...3230",
      "remote_start_enabled": true,
      "calendar_enabled": true,
      "notifications_enabled": true,
      "backseat_token": null,
      "backseat_token_updated_at": null
    }
  ],
  "count": 1
}

All personal information has been shortened with three dots in the middle, in case you were wondering. This list will now provide you the basic information for all vehicles registered under your personal account. The most important information is going to be a personal identifier for use within your application if you plan to use more than one vehicle, and that is the id, not the vehicle_id or vin. This is essential, or else your commands and requests cannot be accounted for and you will receive a 404 message.

Now you probably want to do some stuff with your Tesla and, for example, would like to request its battery information. We can do that by throwing a GET request at the correct address, https://owner-api.teslamotors.com/api/1/vehicles/{id}/data_request/charge_state, and parsing through the returned JSON object. The web address has to be assembled individually with the vehicle’s id, neither vehicle_id, nor the digit 1, but the very long id that came with the vehicle list. Additionally, same as above: include the Authorization header with your bearer token and you should get a response like this:

{
  "response": {
    "charging_state": "Disconnected",
    "charge_limit_soc": 90,
    "charge_limit_soc_std": 90,
    "charge_limit_soc_min": 50,
    "charge_limit_soc_max": 100,
    "charge_to_max_range": false,
    "battery_heater_on": null,
    "not_enough_power_to_heat": null,
    "max_range_charge_counter": 0,
    "fast_charger_present": null,
    "fast_charger_type": "",
    "battery_range": 130.46,
    "est_battery_range": 123.91,
    "ideal_battery_range": 104.37,
    "battery_level": 44,
    "usable_battery_level": 44,
    "battery_current": null,
    "charge_energy_added": null,
    "charge_miles_added_rated": 0.0,
    "charge_miles_added_ideal": 0.0,
    "charger_voltage": null,
    "charger_pilot_current": null,
    "charger_actual_current": null,
    "charger_power": null,
    "time_to_full_charge": 0.0,
    "trip_charging": null,
    "charge_rate": 0.0,
    "charge_port_door_open": null,
    "motorized_charge_port": false,
    "scheduled_charging_start_time": null,
    "scheduled_charging_pending": false,
    "user_charge_enable_request": null,
    "charge_enable_request": true,
    "eu_vehicle": true,
    "charger_phases": null,
    "charge_port_latch": "",
    "charge_current_request": 32,
    "charge_current_request_max": 32,
    "managed_charging_active": false,
    "managed_charging_user_canceled": false,
    "managed_charging_start_time": null
  }
}

Feels good to have gotten so far, eh? Took me a while to figure it all out. Contrary to the apiary documentation, for example, the vehicle ID in the URL is NOT a simple 1 or 2, depending on how many vehicles you have in your account, but the actual unique ID that is assigned to your Tesla.

Okay, now let’s take it a step further and go crazy. How about we set our charge limit to 85%? So this time we need to throw a POST request at the correct address from Tesla, https://owner-api.teslamotors.com/api/1/vehicles/{id}/command/set_charge_limit, and let’s see if this was actually successful. Make sure you add the bearer token in your headers and the id of the vehicle in the URL. The desired percentage has to go into the HTTP body in JSON format, similar to the request of the access_token. So, the header information needs to be extended with the following:

  • Content-Type: application/json; charset=utf-8
  • Authorization: Bearer e5f…e1d

Your data content will then go in the HTTP body as follows:

  • percent: 85 (alternatively "85")

You can use the number as both a string or an integer, so basically with or without the quotation marks. Again, contrary to the apiary documentation, do not add ?percent=85 at the end of the URL, this will most likely do nothing. It didn’t do anything for me. The resulting response looks like this:

{
  "response": {
    "reason": "",
    "result": true
  }
}

Conclusion

The apiary documentation is a very helpful resource for the various functions of the Tesla API and the parameters they take, but the actual “making it work” seems to be quite off there. It’s been a great first start knowing how to get to work with the API, and the next step in the game will be to implement the Streaming API for the Tesla, which should provide additional information on the vehicle’s current state. But that’s going to be another blog post sometime in the future. Have fun and good luck coding! 😊

Last updated: November 4, 2026
Built with SvelteKit + Tailwind
Privacy