# \[Unsupported\] Homey v2 REST API

**URL:** <https://community.homey.app/t/unsupported-homey-v2-rest-api/7268>\
**Category:** Developers\
**Created:** [January 18, 2019, 3:07pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268 "2019-01-18T15:07:04Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![TTXy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ttxy/32/11223_2.png) [@TTXy](https://community.homey.app/u/TTXy)\
**Post date:** [May 23, 2019, 4:19pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/41 "2019-05-23T16:19:45Z")

</div>

I am able to get the token information from from homey.ink, like:

_client\_id=5cbbXXXXXXXXXX009fXXXXe46&client\_secret=gvhs0gXXXXxxxxXXXXxxxXXkuo1uvs8&grant\_type=authorization\_code&code=9c64eXXXXXXXXXXXXXXXXX584da7_

Then I try to use curl with the following command on the first request:

_curl -d “client\_id=5cbbXXXXXXXXXX009fXXXXe46&client\_secret=gvhs0gXXXXxxxxXXXXxxxXXkuo1uvs8&grant\_type=authorization\_code&code=9c64eXXXXXXXXXXXXXXXXX584da7” -H “Content-Type: application/x-www-form-urlencoded” -X POST [https://api.athom.com/oauth2/token](https://api.athom.com/oauth2/token)_

Then I get the response mentioned over…

---

<div class="post-metadata">

**Author:** ![robertklep](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/robertklep/32/160628_2.png) [@robertklep](https://community.homey.app/u/robertklep)\
**Post date:** [May 23, 2019, 4:31pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/42 "2019-05-23T16:31:28Z")

</div>

Works fine for me (on macOS):

```auto
$ curl -d 'client_id=5cbb504da1fc782009f52e46&client_secret=gvhs0gebgir8vz8yo2l0jfb49u9xzzhrkuo1uvs8&grant_type=authorization_code&code=XXX' -H 'content-type: application/x-www-form-urlencoded' -XPOST https://api.athom.com/oauth2/token
{"token_type":"bearer","access_token":"YYY","expires_in":3660,"refresh_token":"ZZZ"}

```

---

<div class="post-metadata">

**Author:** ![TTXy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ttxy/32/11223_2.png) [@TTXy](https://community.homey.app/u/TTXy)\
**Post date:** [May 23, 2019, 4:58pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/43 "2019-05-23T16:58:51Z")

</div>

Just tried one more time, now I got this:

_ **{“code”:400,“error”:“invalid\_grant”,“error\_description”:“Code has expired”}** _

I will try close down the browser and clear cache and try one more time…

---

<div class="post-metadata">

**Author:** ![robertklep](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/robertklep/32/160628_2.png) [@robertklep](https://community.homey.app/u/robertklep)\
**Post date:** [May 23, 2019, 5:04pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/44 "2019-05-23T17:04:43Z")

</div>

That means that you weren’t quick enough 😉 The code that you cut-and-paste from the browser has a very short expiry time.

---

<div class="post-metadata">

**Author:** ![Niels](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/niels/32/89_2.png) [@Niels](https://community.homey.app/u/Niels)\
**Post date:** [May 23, 2019, 5:21pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/45 "2019-05-23T17:21:24Z")

</div>

Looks good to me. Weird.

---

<div class="post-metadata">

**Author:** ![TTXy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ttxy/32/11223_2.png) [@TTXy](https://community.homey.app/u/TTXy)\
**Post date:** [May 23, 2019, 6:28pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/46 "2019-05-23T18:28:38Z")

</div>

Got it working now… 😀

---

<div class="post-metadata">

**Author:** ![Lammy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lammy/32/11436_2.png) [@Lammy](https://community.homey.app/u/Lammy)\
**Post date:** [May 28, 2019, 6:25am UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/47 "2019-05-28T06:25:08Z")

</div>

Here’s how to have your application login to homey with just your e-mail address and password (once) and obtain a refresh token for subsequent access.  
Notice, the refresh token will expire, either by expiration or revocation.  
There are quite a few more things to discover, but this will get you going.

In the following steps, I didn’t register a new application (probably possible, but I didn’t look into that yet), I just borrowed the client\_id and client\_secret from [developer.athom.com](http://developer.athom.com) (client\_id=598d85a330e1bb0c0d75b8eb and client\_secret=ba93fc861b204732607169fb29c2708f1da7e17f). Other combinations for client\_id and client\_secret will also work (for example homey.ink), as long as the redirect\_uri matches.

Step 1, get a JWT with your credentials.  
HTTPS-POST your e-mail address and password, form-url-encoded, to [accounts.athom.com/login](http://accounts.athom.com/login).  
No client\_\* needed at this time.  
The JSON reply is the JWT as {“token”: “`jwt`”}

Step 2, obtain a delegation code.  
HTTPS-GET [accounts.athom.com//authorise?client\_id=xxx&redirect\_uri=](http://accounts.athom.com//authorise?client_id=xxx&redirect_uri=)`uri`&response\_type=code&user\_token=`JWT from previous step`  
Since I used the client\_id from [developer.athom.com](http://developer.athom.com), the `uri` in this case is the aforementioned. The redirect\_uri is important and will be checked (as it should be)  
Be aware, the HTTP result will be a 302 (redirect).  
The location-header contains a query parameter ‘code’. It’s value is the delegation code. The header looks like: “location: https://`redirect_uri`?code=89bc40ceXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX29”.

Step 3, get an access token  
HTTPS-POST [api.athom.com/oauth2/token](http://api.athom.com/oauth2/token), form-url-encoded  
Body: client\_id=XXX&client\_secret=YYY&grant\_type=authorization\_code&code=`Delegation code from previous step`  
The JSON result looks like this in readable format:  
{  
“access\_token”: “51163d8xxxxxxxxxxxxxxxx8282579f8fe77ee”,  
“expires\_in”: 3660,  
“refresh\_token”: “f7d635axxxxxxxxxxxxxxxx1c2a258f4e33d15b”,  
“token\_type”: “bearer”  
}  
Use the access\_token for the next step, but also keep the refresh\_token. You will need the refresh\_token in the future to obtain a new bearer code.

Step 4, obtain a JWT to login to your homey  
HTTPS-POST [api.athom.com//delegation/token?audience=homey](http://api.athom.com//delegation/token?audience=homey)  
Add an http-header: Authorization: Bearer `access_token from previous step or step 6`  
The JSON result contains just the JWT.

Step 5, login to homey  
HTTPS-POST `uri`/api/manager/users/login  
Body: {"token”:”`JWT from step 4`”}  
The reply is the desperately sought bearer token in JSON format.  
`uri` can be a number of things:

- The fastest option is homey’s local IP address.
- The second is a local qualified DNS name.
- Another option is: [w-x-y-z.homey.homeylocal.com](http://w-x-y-z.homey.homeylocal.com) (w-z = the local IP address bytes).
- More options exist, all through the cloud and pretty much equally slow.

The bearer code will expire after 24 hours. To obtain a new one without user credentials, see step 6.

Step 6, refresh the bearer token  
The bearer token expires every 24 hours and with good reason.  
If you saved the refresh\_token from step 3, you can obtain a new access\_token and hence a new bearer token. Note: this will not go on indefinitely. At some point you will have to login again.  
HTTPS-POST [api.athom.com/delegation/token?audience=homey](http://api.athom.com/delegation/token?audience=homey), form-url-encoded.  
Body: client\_id=XXX&client\_secret=YYY&grant\_type=refresh\_token&refresh\_token=\<refresh\_token\>  
The response is similar to the response in step 3. Use the access\_token to repeat steps 4 and 5. Keep the refresh\_token for the next refresh (The refresh\_token may change).

With the access\_token received in step 3 or 6 you can find useful information like cloud id and homey’s ip address:  
HTTPS\_GET [api.athom.com/user/me](http://api.athom.com/user/me)  
Add header: Authorization: Bearer \<access\_token from step 3 or 6\>

---

<div class="post-metadata">

**Author:** ![Rom](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/rom/32/11038_2.png) [@Rom](https://community.homey.app/u/Rom)\
**Post date:** [June 4, 2019, 12:56pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/48 "2019-06-04T12:56:56Z")

</div>

Lammy I have a problem with step 2. Step 1 is working. In step 2 the page that is returned is not the page (302) you describe with a location header. When i use client\_id and redirect\_uri from homey.ink. It is the page where I should allow the requested grants. No location header here.

---

<div class="post-metadata">

**Author:** ![Lammy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lammy/32/11436_2.png) [@Lammy](https://community.homey.app/u/Lammy)\
**Post date:** [June 5, 2019, 9:44pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/49 "2019-06-05T21:44:53Z")

</div>

Hmm, I see @Rom. You need an extra step between 2 and 3, let’s split step 2 in 2a and 2b. Step 2a is the same as the former step 2 from your side, but with a different reply (http 200 iso 302). The extra step 2b is to mimic the form returned in step 2a, as if you pressed the Allow button, i.e. post the same parameters using form-url-encoding.  
Something like this: `_csrf=xxxxxx&resource=resource.homey.yyyyyyyy&allow=Allow`  
All the parameters are in the returned html from step 2a.  
The seasurf (\_csrf) is a bit puzzling to me at the moment, because it is in the returned html (at least that’s how it appears in my browser’s console) and it escapes me how this should prevent forgery. Another puzzling thing is that step 2a returns a csrf cookie with a different value. You might need to add the cookie from 2a to the headers for 2b, I can’t tell yet.  
My code is running on an embedded system with a self-built https client that doesn’t support chunked compressed bodies yet, so I can’t test it at the moment. I hope to find some time next week to extend my https client and/or play around with curl and see what I can find out.  
By the way, if you split the jwt from step 1 by the dots(.) and b64decode the middle part, you’ll get the id of the homey that you’ve logged in to (The y’s in resource=resource.homey.yyyyyyyy).  
Hopefully this gets you going.

---

<div class="post-metadata">

**Author:** ![Rom](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/rom/32/11038_2.png) [@Rom](https://community.homey.app/u/Rom)\
**Post date:** [June 6, 2019, 7:25am UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/50 "2019-06-06T07:25:15Z")

</div>

@Lammy. Thank you for your research so far. I will try your suggestions next weekend.

---

<div class="post-metadata">

**Author:** ![Sebastien\_Langolf](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/sebastien_langolf/32/12919_2.png) [@Sebastien\_Langolf](https://community.homey.app/u/Sebastien_Langolf)\
**Post date:** [July 31, 2019, 4:41pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/51 "2019-07-31T16:41:19Z")

</div>

Hi I have tried this command, but it’s appear it’s wrong ! How can I update a swith from on to off or off to on with http link?

http://\<HOMEY\_IP\>/api/manager/devices/device/ff469433-66b3-458d-ad73-14530d8f9b39/capability/onoff

regards

---

<div class="post-metadata">

**Author:** ![ismar.slomic](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ismar.slomic/32/13411_2.png) [@ismar.slomic](https://community.homey.app/u/ismar.slomic)\
**Post date:** [August 1, 2019, 9:34am UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/52 "2019-08-01T09:34:31Z")

</div>

> [@Lammy](#):
>
> Here’s how to have your application login to homey with just your e-mail address and password (once) and obtain a refresh token for subsequent access.

Does this solution work only on localhost or other hosts as well? This is most related to the redirect URL, which is not editable in Developer portal and is set to `http://localhost, http://localhost/oauth2/callback`, because Athom does not provide authentication in production yet.

---

<div class="post-metadata">

**Author:** ![Lammy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lammy/32/11436_2.png) [@Lammy](https://community.homey.app/u/Lammy)\
**Post date:** [August 1, 2019, 1:02pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/53 "2019-08-01T13:02:24Z")

</div>

> [@Sebastien\_Langolf](#):
>
> How can I update a swith from on to off or off to on with http link?
> 
> http://\<HOMEY\_IP\>/api/manager/devices/device/ff469433-66b3-458d-ad73-14530d8f9b39/capability/onoff

Your url is correct. Use the PUT method, put this in the body: {“value”:false} and send this header “Content-Type: application/json” along. Use `true` to switch on and `false` to switch off.

---

<div class="post-metadata">

**Author:** ![Lammy](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/lammy/32/11436_2.png) [@Lammy](https://community.homey.app/u/Lammy)\
**Post date:** [August 1, 2019, 1:17pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/54 "2019-08-01T13:17:52Z")

</div>

> [@ismar.slomic](#):
>
> Does this solution work only on localhost or other hosts as well?

Localhost doesn’t work. Localhost refers to the machine your own code is running on, but you want to connect to Athom’s api host. Use [api.athom.com](http://api.athom.com) instead.  
Note: localhost works only on Athom’s server, if localhost resolves to an address for the same machine as [api.athom.com](http://api.athom.com).

---

<div class="post-metadata">

**Author:** ![ismar.slomic](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ismar.slomic/32/13411_2.png) [@ismar.slomic](https://community.homey.app/u/ismar.slomic)\
**Post date:** [August 1, 2019, 1:23pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/55 "2019-08-01T13:23:08Z")

</div>

> [@Lammy](#):
>
> Localhost doesn’t work. Localhost refers to the machine your own code is running on, but you want to connect to Athom’s api host. Use [api.athom.com](http://api.athom.com) instead.

I got that, but in Step 2 you need to set query param `redirect_uri`, together with the `client_id`. Both values are found at Athom Developer Portal. `redirect_uri` is `localhost` in Developer Portal. This works when I test your steps locally on my machine, but if I deploy my code to for instance AWS, I guess `redirect_uri` cant be localhost

---

<div class="post-metadata">

**Author:** ![robertklep](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/robertklep/32/160628_2.png) [@robertklep](https://community.homey.app/u/robertklep)\
**Post date:** [August 1, 2019, 1:28pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/56 "2019-08-01T13:28:29Z")

</div>

The `redirect_uri` targets (interactive) browsers, but this method performs authentication programmatically. Even _if_ your code would get a redirect to localhost, you can ignore it and extract the token.

---

<div class="post-metadata">

**Author:** ![ismar.slomic](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ismar.slomic/32/13411_2.png) [@ismar.slomic](https://community.homey.app/u/ismar.slomic)\
**Post date:** [August 1, 2019, 1:30pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/57 "2019-08-01T13:30:06Z")

</div>

So I can just set the redirect\_uri to localhost, according to Athom Developer Portal. Since web browser will not follow/catch the redirect anyway

---

<div class="post-metadata">

**Author:** ![robertklep](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/robertklep/32/160628_2.png) [@robertklep](https://community.homey.app/u/robertklep)\
**Post date:** [August 1, 2019, 1:32pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/58 "2019-08-01T13:32:23Z")

</div>

The browser _will_ catch it. The method described is meant to be used from server-side code.

You can try following the steps using a CLI client like cURL to see how it works.

---

<div class="post-metadata">

**Author:** ![ismar.slomic](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/ismar.slomic/32/13411_2.png) [@ismar.slomic](https://community.homey.app/u/ismar.slomic)\
**Post date:** [August 1, 2019, 1:35pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/59 "2019-08-01T13:35:24Z")

</div>

Aha, now I got it! I was thinking that these steps should be performed server-side, otherwise redirects will be caught by the browser. Thanks for the clarification!

Im just sad to see all these creative workarounds to get the authentication working seamlessly. If Athom just provided OAuth / OIDC authentication flow, this should be unnecessary

---

<div class="post-metadata">

**Author:** ![robertklep](https://sea1.discourse-cdn.com/flex025/user_avatar/community.homey.app/robertklep/32/160628_2.png) [@robertklep](https://community.homey.app/u/robertklep)\
**Post date:** [August 1, 2019, 1:43pm UTC](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268/60 "2019-08-01T13:43:06Z")

</div>

I agree. It was promised a year or so ago, when Homeydash development started, but never materialized.

[Previous page](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268.md?page=2)

[Next page](https://community.homey.app/t/unsupported-homey-v2-rest-api/7268.md?page=4)
