Genie Partner Integration
Table of Contents
Setup
Before starting your integration, you need to make sure you have the following items:
- A client ID (provided by Genie)
- A client Secret (provided by Genie)
- A base API URL to make API calls (provided by Genie)
- An API Key
The base API URL will be of the form yourcompanyname.smartgarage.systems.
Note that all three of these values are for development purposes only.
Once you have integrated your system, you can reach out to us to begin
migration into the production system. At that point, the above items will
be regenerated for you and sent via a secure transfer mechanism.
If you do not have any of these items, please reach out to us so that we can set this up for you.
Branding
Our system supports two brands, Overhead Door Company (OHD) and Genie Company. The two apps are OHDAnywhere and Aladdin Connect, respectively. In order for us to show the correct branding to the users, during the linking phase we will ask you to direct them to the correct login page based on a path parameter of either 'ohd' or 'aladdin' (described in detail below). After the initial linking phase (OAuth2.0 flow), the brand will no longer be necessary to track as all requests and callbacks will be done with the same system.
OAuth 2.0 Flow
In order to gain access to a user's devices, your application will need to use the OAuth 2.0 protocol. First, make sure you have everything described in the Setup section above.
The OAuth 2.0 flow is as follows:
User Login
When a user requests to add their Genie device to your service, they should be forwarded to the following login URLs depending on brand:
- OHDAnywhere:
https://app.ohdanywhere.net/login?response_type=code&client_id=<client-id>&redirect_uri=<redirect-uri>&state=<state> - Aladdin Connect:
https://app.aladdinconnect.net/login?response_type=code&client_id=<client-id>&redirect_uri=<redirect-uri>&state=<state>
Using the following parameters:
- <client-id> = The client ID provided by Genie
- <redirect-uri> = A URL for an endpoint in your system that will accept the callback described below
- <state> = Optional parameter that will be echoed back to your callback URL. For example, you could use this for a user ID to be able to associate the token you receive with a user in your system
NOTE: response_type parameter should be set to the literal value code exactly as above.
Token Exchange
After the user logs in to their Genie account on that page, our server will call the redirect_uri you supplied above with the following format:
<redirect-uri>?code=<authorization-code>&state=<state>
The <authorization-code> parameter will be a one time use code that you can use to get an access token. The <state> parameter will be whatever you supplied in the <state> parameter above.
Once you have the authorization code supplied in the above callback, you can use it to make the following request to our server:
POST https://<base-url>/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
client_id=<client-id>
client_secret=<client-secret>
code=<authorization-code>
redirect_uri=<redirect-uri>Using the following parameters:
- <client-id> = The provided client ID from above
- <client-secret> = The provided client secret from above
- <authorization-code> = The authorization code you received from us in the callback
- <redirect-uri> = The same redirect URI you provided in the first step
You will receive a 200 status JSON response like the following:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTc2MjM5MDIyfQ.ZgYY-8GOvkCjnSadE0kXx_Ddu7h5bNMamsiud8y9ne4",
"token_type": "Bearer",
"expires_in": 3600
}The access_token is the token that you will use to access our endpoints (described in the API section below). This is a short-lived token (1 hour), so you will also need to store the refresh_token so that you can get new tokens when needed (described below).
Refreshing Tokens
When a token has expired, you will need to get a new token using the stored refresh_token provided in the initial flow above. To do this, you can make the following call:
POST https://<base-url>/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
client_id=<client-id>
refresh_token=<refresh-token>Using the following parameters:
- <client-id> = The provided client ID from above
- <refresh-token> = The refresh token you stored during the initial token exchange (described above)
You will receive a 200 status JSON response like the following:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"token_type": "Bearer",
"expires_in": 3600
}NOTE: We will rotate refresh tokens once a year. In this case, you will get a new refresh token (example response below). You should store this new refresh token and discard the old one.
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTc2MjM5MDIyfQ.ZgYY-8GOvkCjnSadE0kXx_Ddu7h5bNMamsiud8y9ne4",
"token_type": "Bearer",
"expires_in": 3600
}API
The next section gives an overview of the API for interacting with Genie devices. This assumes you have implemented the above described OAuth 2.0 flow and are able to get access tokens.
Authorization
Every endpoint described in this section requires an authorization header like:
Authorization: Bearer <access-token>
Where the <access-token> is the token you received in the above described OAuth 2.0 flow. You should have an access token for each user that has integrated with Genie, as this token will be used to identify which Genie user you are making actions on behalf of.
You will also need to provide the API KEY provided in the setup like:
X-API-KEY: <api-key>
Device Discovery
Device discovery can be used to get a list of all the Genie devices in the user's account. This is typically used when the user initially signs into their Genie account. You can also poll this every 12-24 hours to make sure you have all the devices in their account. However, this is not meant to be used to synchronize the state of the devices, so there should not be any need to call this more frequently than every 12-24 hours. There are better methods of device synchronization described later in this section.
You can access this resource by making a GET call to the /devices endpoint. The response will look like:
[
{
"ownership": "owner",
"name": "Genie Device 1",
"id": "A1B2C3D4E5F6",
"status": "online",
"productFamily": "idcm",
"doors": [
{
"name": "Genie Door",
"index": 1,
"link_status": "online",
"battery": 100,
"status": "closed"
}
]
},
{
"ownership": "owner",
"name": "Genie Device 2",
"id": "F6E5D4C3B2A1",
"status": "online",
"productFamily": "edcm",
"doors": [
{
"name": "Door 1",
"index": 1,
"link_status": "online",
"battery": 100,
"status": "closed"
},
{
"name": "Door 2",
"index": 2,
"link_status": "online",
"battery": 100,
"status": "open"
}
]
}
]As mentioned above, this is only meant as part of a "discovery" phase. Further synchronization can be done using other methods described later in this section.
Door State
After doing the initial discovery described above, you can request the state of a specific door by making a GET call to the following endpoint:
/devices/{deviceId}/doors/{doorIndex}
Where {deviceId} is the id field from the above discovery response, and the {doorIndex} is the index field from the specific door you would like to receive the state for. This will give a response like:
{
"linkStatus": "connected",
"device_status": "online",
"fault": "none",
"id": "A1B2C3D4E5F6",
"door_index": 1,
"status": "closed"
}Door State Values
The following values are possible for the device_status:
online: The device is connected to the networkoffline: The device is not connected to the network
The following values are possible for the fault:
none: There is no faultul_lockout: The device is in "UL Lockout" mode and must be manually operated to remove this faultmove_abort: The device is in "Move Abort" mode. This could be because of an obstruction or other issues. The user can refer to the device manual for more information on how to clear this fault.
The following values are possible for the status:
open: The door is openopening: The door is in the process of openingtimeout_opening: The door timed out waiting on an open to completeclosed: The door is closedclosing: The door is in the process of closingtimeout_closing: The door timed out waiting on a close to completeunknown: The door state is unknown. The door is likely not fully setup. User should refer to the device manual for more information.
The following values are possible for the linkStatus:
unknown: The device is not fully setup. User should refer to the device manual for more information.not_config: The device is not fully setup. User should refer to the device manual for more information.paired: The DPS and the device are paired, but the DPS is not currently connected.connected: The DPS and the device are connected.
Command
In order to operate a door, you must send a "door command" using a POST call to the following endpoint:
/devices/{deviceId}/doors/{doorIndex}/command
Where {deviceId} is the id field from the above discovery response, and the {doorIndex} is the index field from the specific door you would like to operate. You must also send a JSON body like the following:
{
"command": "<door-command>"
}where <door-command> is either open or close. If the command is received, you will receive a 200 status response. This 200 status only means we received the command. The actual opening or closing of the door will be sent later using the webhook endpoint described below.
User
If you need to get info about the Genie user account, you can send a GET request to the endpoint /user. Note that no ID is needed since the access token in the authorization header will be used to identify the user. The JSON response will look like the following:
{
"name": "Genie User",
"id": "643261cf-7252-459b-9ed6-61ab76181c0d",
"email": "example@genie.com"
}Webhook
The above section describes how you can use our API to issue commands and synchronize state, but what about operations that happen outside of your application? We provide a way for you to listen to those by allowing you to link a "webhook" URL, which is a callback URL that we will send requests to whenever a user adds a device, removes a device, or a device's state changes. In this way, you can get real time updates to a user's devices without having to poll the above API. Because of this, we recommend you do not do any polling of the above API more frequently than once or twice a day. Ideally, after the initial discovery phase, you should be able to keep all device state in sync by setting up this webhook.
The URL you provide to us for this webhook will be called with a POST request every time a device is added or removed, or whenever linked device's state changes. For add and update events, there are enumerated values sent in the event body. They are defined at the bottom of this section. Next we will give examples of the three event types this webhook will be called with (these payloads will be the body of the request).
Insert
This event will be sent any time a new device is added to a user's account.
{
"eventType": "Insert",
"inserted": [
{
"device_id": "FC45C315EE248",
"email": "genie@test.com",
"door_index": 1,
"door_status": 4,
"link_status": 3,
"device_status": 1,
"timestamp": "2023-05-24T14:58:38.188Z"
}
],
"updated": [],
"removed": []
}Note that the inserted field is an array, as there may be multiple insert events sent in a single request. These events contain enumerated values for the door status, link status and device status fields. Those enumerations are defined later in this section.
Update
This event will be sent when any of the fields are changed. Note that a single event can represent more than one change.
{
"eventType": "Update",
"inserted": [],
"updated": [
{
"device_id": "FC45C315EE248",
"email": "genie@test.com",
"door_index": 1,
"door_status": 4,
"link_status": 3,
"device_status": 1,
"fault": 0,
"timestamp": "2023-05-24T14:58:38.188Z",
"last_command_id": 1725036098,
"last_command_outcome": "SUCCESS" // OPTIONAL
}
],
"removed": []
}Optional Command Outcome Field
If (and only if) there is an ongoing command, the last_command_outcome field will be one of the following values:
SUCCESS: The command was successful
IN_PROGRESS: The command is still in progress
TIMEOUT: The command timed out
DUPLICATE: The door was already in the desired state
NOT_NEEDED: The door was already in the desired state
BUSY: The door was already in motion
OBSTRUCTION: There was something in the way of the door sensors
UNKNOWN: The command failed for an unknown reason
If there is not an ongoing command, the last_command_outcome field will not be present.
Note that the updated field is an array, as there may be multiple update events sent in a single request. These events contain enumerated values for the door status, link status and device status fields. Those enumerations are defined later in this section.
Remove
This event will be sent any time a device is removed from a user's account.
{
"eventType": "Remove",
"inserted": [],
"updated": [],
"removed": [
{
"device_id": "FC45C315EE248",
"door_index": 1,
"email": "genie@test.com"
}
]
}Note that the removed field is an array, as there may be multiple remove events sent in a single request.
Triggering of Events
Insert Event
You can trigger this event by adding a new device to your account using our mobile app.
Update Event
You can trigger this event by the following methods:
- Opening or closing a door using the wall console button or an RF remote. Note that this
will not include a
last_command_outcomefield. - Opening or closing a door using the mobile app. This will include a
last_command_outcomefield. - Opening or closing a door using the API described above. This will include a
last_command_outcomefield. - Unplugging a device or otherwise removing it from network connectivity. This can take up to 3 minutes for our system to detect, after which you will receive an update event with device status as offline (0).
- If you have a door with STB sensors (laser sensors), operate the door using the mobile app (or the API) with the sensors blocked twice in a row. This should result in consecutive failed remote commands. After the second failure, the device will go into "UL Lockout" mode, which will be sent in an update event with fault code 1. To clear the fault, you must operate the door using the wall console button or an RF remote successfully twice in a row.
- If you have a retrofit device with a door sensor, operate the door using the mobile app (or the API) but
do not move the sensor. After approximately 120 seconds, you should see an
OPEN_TIMEOUTorCLOSE_TIMEOUTstate.
For other fault states, you can set up a meeting with us where we can manually put the device into other fault states and trigger the event for you to test.
Remove Event
You can trigger this event by deleting a device from your account using our mobile app.
Enumerations
Door State
enum {
UNKNOWN = 0,
OPEN = 1,
OPENING = 2,
OPEN_TIMEOUT = 3,
CLOSED = 4,
CLOSING = 5,
CLOSE_TIMEOUT = 6
}Link Status
enum {
UNKNOWN = 0,
NOT_CONFIGURED = 1,
PAIRED = 2,
CONNECTED = 3,
SYNC_LOST = 4
}Device Status
enum {
ONLINE = 1,
OFFLINE = 0
}Device Fault
enum {
NONE = 0,
UL_LOCKOUT = 1,
INTERLOCK = 2,
NOT_SAFE = 3,
WILL_NOT_MOVE = 4
}Usage Limits
In order to ensure our API remains performant and available for all users, we have implemented usage limits on our API. These limits are also designed to limit our financial exposure to abuse of the API. There are two types of limits:
- Rate Limits: These limits are applied to the number of requests you can make to our API in a given time period. The default rate limit is 100 requests per second.
- Daily Quota: This is the total number of requests you can make to our API in a 24-hour period. The default daily quota is 10,000 requests.
The default limits of 100 RPS and 10,000 RPD should be sufficient for most use cases. By integrating the webhook described above and not polling for state updates, you can typically avoid hitting these limits.
If you find that you need higher limits, please reach out to us to discuss your use case and we will see if we can accommodate your needs.