Akiles API Reference

Akiles API

API Endpoint
https://api.akiles.app/v2
Contact: dario@akiles.app
Version: 2.0

Changelog

Version 2.0

Released July 2020

New features

  • Members can now have multiple email addresses.
  • Members can now have multiple magic links.
  • A member can have email addresses and magic links at the same time.
  • A member can now be associated to multiple groups, with each association having its own start and end date/times.

Having multiple email addresses is useful for hotel room reserves where you have multiple guests in the same room. Now you can create the reserve as a single member that grants access to all guests.

Per-group start/end times is useful for room reservations: the same member can have multiple reservations for different rooms at different times, and he'll only be able to enter each room during the allowed time.

API changes

  • Removed member fields: type, email, member_group_ids
  • Removed endpoints /members/{member_id}/magic_link
  • Added endpoints /members/{member_id}/emails
  • Added endpoints /members/{member_id}/magic_links
  • Added endpoints /members/{member_id}/group_associations

Version 1.0

Initial API release

Versioning

The major version is indicated in the URL. For example https://api.akiles.app/v1 vs https://api.akiles.app/v2. The minor version is not indicated anywhere, since minor versions only do backwards-compatible changes. A client designed for API version v2.0 should work unmodified on version v2.1, provided it follows the compatibility policy outlined below.

We will release new minor versions with only backwards-compatible changes. We consider the following changes backwards-compatible:

  • Adding new endpoints.
  • Adding new HTTP methods to existing endpoints.
  • Adding new optional fields to request objects.
  • Adding new fields to response objects.
  • Adding new possible values to enum fields.
  • Relaxing request validation rules. For example, a field couldn't be null before and now it can.

Keep these in mind when developing your integration. For example, when parsing API responses, ignore unknown received fields instead of erroring.

Ocasionally, when backwards-incompatible changes are necessary for the healthy evolution of the platform, we will also release new major API versions. In this case, the previous major version will be supported for at least 6 months after the launch of the new major version.

Authentication types

There are two ways to authenticate to the API: API keys and OAuth.

Use API keys if you're developing integrations that you will only use with your own Akiles organization. This is the easiest and simplest way to get started, and the security benefits of OAuth don't apply to you anyway.

Use OAuth if you want other people to use your integration. The most common use case is if you are developing a SaaS and want your customers to be able to enable your integration with their own Akiles organizations.

Additionally, OAuth is required to get your application/integration listed in the Applications tab in the Akiles admin panel. Listing your application will make it discoverable to all Akiles customers.

API key authentication

API keys are static keys that can be used to make calls to the Akiles API.

To create an API key, login to the Akiles admin panel, and go to API -> API keys and create one. For security, you will only be able to see the full value of the API key once, when creating it.

To use the API key, include an Authorization: Bearer header with it:

Authorization: Bearer ak_3pbzqfe...

All API keys have full read-write permissions, equivalent to organization administrators. All the actions performed with the API key are attributed to it in the events.

OAuth authentication

OAuth authentication uses the standard RFC-6479 OAuth 2.0 protocol. It allows your app to interactively request access to customers' Akiles organizations and obtain access tokens for them. This makes the experience smoother and more secure, since the customer doesn't have to manually copy and paste a sensitive API key.

This section is not intended to be a full explanation on how OAuth works, just a quick reference to get started. For more info, consult online documentation about OAuth.

Client ID and Client Secret

Your OAuth application needs a Client ID and a Client Secret to operate.

  • The Client ID is considered public, it is OK to expose it to frontends (and is in fact necessary to do so).
  • The Client Secret must be maintained confidential since it is used to obtain access tokens. Always use it from your server, never send it or expose it to your frontend.

To obtain your application's Client ID and Secret, contact support.

Token types

  • Access token: used to make API calls, expires 1 hour after issuance.
  • Refresh token: used to obtain new access tokens when they expire.

There are multiple types of Access and Refresh tokens depending on how they've been obtained

  • Session access/refresh token: This token is associated to an organization and a particular user's session. They get revoked in these cases:
    • The user logs out
    • The user's session expires due to inactivity
    • The user is removed as an admin from the organization
    • The application is deauthorized from the organization
  • Organization access/refresh token: This token is only associated to an organization. They get revoked in these cases:
    • The application is deauthorized from the organization

When doing the authorization flow you will receive session access/refresh tokens. If you need persistent access to the organization (e.g. after the user logs out), you can do so by requesting the offline scope, and exchanging the session token for organization access/refresh tokens (see below).

Authorization flow

  1. Generate a cryptographically-secure random string state and store it somewhere you can access it later (e.g. a cookie)
  2. Start the flow by redirecting the user to the following URL:
https://auth.akiles.app/oauth2/auth?client_id=CLIENT_ID_HERE>&redirect_uri=https://your-app.example.com/redirect&response_type=code&scope=full_read_write&state=STATE_HERE
  1. The Akiles authorization server will prompt the user to choose a user account and organization.
  2. The Akiles authorization server will ask the user to authorize your requested scopes.
  3. The user gets redirected to your redirect_uri:
https://your-app.example.com/redirect?code=CODE_HERE&scope=full_read_write&state=STATE_HERE
  1. Check the state you have received matches the original state you stored. If it doesn't, abort. This is necessary to protect against CSRF / session poisoning attacks.
  2. Exchange the authorization code for the access and refresh tokens.
POST https://auth.akiles.app/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
client_id=CLIENT_ID_HERE
client_secret=CLIENT_SECRET_HERE
code=CODE_HERE
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token": "ACCESS_TOKEN_HERE",
  "expires_in": 3599,
  "refresh_token": "REFRESH_TOKEN_HERE",
  "scope": "full_read_write",
  "token_type": "bearer"
}
  1. You're done! Save the access token and refresh token.

You can now use the access token to make API calls on behalf of the user's organization. The access token expires in 1 hour. You can obtain new, fresh access tokens with the refresh token.

Refresh token flow

POST https://auth.akiles.app/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
client_id=CLIENT_ID_HERE
client_secret=CLIENT_SECRET_HERE
refresh_token=REFRESH_TOKEN_HERE
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token": "NEW_ACCESS_TOKEN_HERE",
  "expires_in": 3599,
  "refresh_token": "NEW_REFRESH_TOKEN_HERE",
  "scope": "full_read_write offline",
  "token_type": "bearer"
}

Store both the new access and refresh tokens. The old refres token, once used, is no longer guaranteed to keep working forever.

Token exchange flow

If you want to exchange a session acess token for an organization access token (see "Token types" above), do the following request:

POST https://auth.akiles.app/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=token_exchange
exchange_to=organization
client_id=CLIENT_ID_HERE
client_secret=CLIENT_SECRET_HERE
refresh_token=SESSION_REFRESH_TOKEN_HERE
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token": "ORGANIZATION_ACCESS_TOKEN_HERE",
  "expires_in": 3599,
  "refresh_token": "ORGANIZATION_REFRESH_TOKEN_HERE",
  "scope": "full_read_write offline",
  "token_type": "bearer"
}

Store the new access and refresh tokens. Note that unlike a normal refresh, a token exchange does not "use up" the original refresh token. You may store both session and organization tokens, and keep using and refreshing both independently.

Scopes

  • full_read_write: read-write access to all the objects. Same as a regular API key, or an administrator user.
  • full_read_only: read-only access to all the objects.
  • offline: allows offline access. You need this to obtain refresh tokens, and to exchange session tokens for organization tokens.

Webhooks

Webhook objects are scoped to your OAuth application. That is, webhooks created with API keys or manually from the admin panel won't be visible to you, and webhooks you create won't be visible to API keys or in the admin panel.

All your application's webhooks in an organization will be deleted when your app gets deauthorized.

You must create/edit/delete webhooks with an organization access token, not with a session access token.

Even if you have read-only access, you can still create/edit/delete webhooks. This allows you to receive real-time updates in an application that only needs to read data from the Akiles organization.

Pagination

The API uses cursor-based pagination. All list endpoints return data in reverse chronological order, and have the following common structure:

GET parameters

  • limit: How many items to fetch, between 1 and 100
  • cursor: Value of cursor_next from a previous request. If not given, it will fetch the most recent items.

Response data

  • data: The received items, in a JSON array.
  • has_next: Whether there are more items to fetch.
  • cursor_next: Cursor to fetch the next page of items. Only present if has_next is true.

Metadata

Most API objects allow you to attach your own, arbitrary key-value metadata in the metadata field. You can use it to store references to primary keys of your database, custom states, etc.

Metadata is visible to anyone with admin or API access to your organization. There is a storage limit of 1024 bytes of metadata per object.

metadata

Key-value metadata

Key-value metadata

object
Example
{
  "key1": "value1",
  "key2": "value2"
}

Organizations

Everything in Akiles APIs belongs to an Organization. An organization represents one Akiles customer and can handle multiple sites, gadgets, etc.. API keys are tied to organizations too, and they give access only to the objects belonging to the organization.

organization

id
string (organization_id)

Unique identifier.

name
string

Name.

is_deleted
boolean

Indicates if the object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "org_3merk33gt1v9ypgfzrp1",
  "name": "SkyCowork",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Get organization

GET /organization
An instance of organization
Response Example (200 OK)
{
  "id": "org_3merk33gt1v9ypgfzrp1",
  "name": "SkyCowork",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit organization

PATCH /organization
metadata
metadata

Key-value metadata

Request Example
{
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of organization
Response Example (200 OK)
{
  "id": "org_3merk33gt1v9ypgfzrp1",
  "name": "SkyCowork",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Sites

A site is a physical place where Akiles gadgets are installed. For example, it can be a building, a floor... Gadgets belong to a particular site.

End users will see one "card" in their app's home screen per site. The site information (email, contact, etc) is displayed in that card.

location

lat
number (float)

Latitude in degrees

lng
number (float)

Longitude

Example
{
  "lat": 41.290485,
  "lng": 2.1829076
}

site_geo

location
location
radius
number (int32)

Radius in meters

Example
{
  "location": {
    "lat": 41.290485,
    "lng": 2.1829076
  },
  "radius": 100
}

site_map

location
location
place_id
string

place_id from Google Maps Places API

address
string

Human-readable address

image_url
string

Map image URL, displayed in the site's header in the app.

Example
{
  "location": {
    "lat": 41.290485,
    "lng": 2.1829076
  },
  "place_id": "string",
  "address": "string",
  "image_url": "string"
}

site

id
string (site_id)

site ID

name
string

Site name

organization_id
string (organization_id)

organization ID

geo
site_geo
map
site_map
phone
string

Phone number. Shown in the site info in the app.

email
string

Email. Shown in the site info in the app.

info
string

Free-form extra information. Shown in the site info in the app.

timezone
string (timezone)

Local time zone of the site.

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "site_3merk33gt21kym11een1",
  "name": "string",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "geo": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "radius": 100
  },
  "map": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "place_id": "string",
    "address": "string",
    "image_url": "string"
  },
  "phone": "string",
  "email": "string",
  "info": "string",
  "timezone": "Europe/Madrid",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List sites

GET /sites
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
site
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "site_3merk33gt21kym11een1",
      "name": "string",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "geo": {
        "location": {
          "lat": 41.290485,
          "lng": 2.1829076
        },
        "radius": 100
      },
      "map": {
        "location": {
          "lat": 41.290485,
          "lng": 2.1829076
        },
        "place_id": "string",
        "address": "string",
        "image_url": "string"
      },
      "phone": "string",
      "email": "string",
      "info": "string",
      "timezone": "Europe/Madrid",
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Get site

GET /sites/{site_id}
site_id
in path
string (site_id)

site ID

An instance of site
Response Example (200 OK)
{
  "id": "site_3merk33gt21kym11een1",
  "name": "string",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "geo": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "radius": 100
  },
  "map": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "place_id": "string",
    "address": "string",
    "image_url": "string"
  },
  "phone": "string",
  "email": "string",
  "info": "string",
  "timezone": "Europe/Madrid",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit site

PATCH /sites/{site_id}
site_id
in path
string (site_id)

site ID

metadata
metadata

Key-value metadata

Request Example
{
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of site
Response Example (200 OK)
{
  "id": "site_3merk33gt21kym11een1",
  "name": "string",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "geo": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "radius": 100
  },
  "map": {
    "location": {
      "lat": 41.290485,
      "lng": 2.1829076
    },
    "place_id": "string",
    "address": "string",
    "image_url": "string"
  },
  "phone": "string",
  "email": "string",
  "info": "string",
  "timezone": "Europe/Madrid",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Gadgets

A gadget is a "thing that can be controlled" by a physical device. Gadgets can be doors, lights, heating, window blinds...

Gadgets are not "physical devices": some devices can have multiple gadgets (gateway_controllers and controllers). Others can have only one (smart locks, for example).

Gadgets can have multiple actions depending on what they are. For example, a normal door will just have an open action, but a blind can have raise and lower actions, and a light can have on and off actions. Actions are identified by their string ID, and they also have a human-friendly name for display in the UI.

gadget_action

id
string

action ID

name
string

Action user-friendly name

Example
{
  "id": "open",
  "name": "Open"
}

gadget

id
string (gadget_id)

gadget ID

organization_id
string (organization_id)

organization ID

site_id
string (site_id)

site ID

name
string

Gadget name

actions
gadget_action
is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "gad_3merk33gt1hnl6pvbu71",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "site_id": "site_3merk33gt21kym11een1",
  "name": "string",
  "actions": [
    {
      "id": "open",
      "name": "Open"
    }
  ],
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List gadgets

GET /gadgets
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
gadget
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "gad_3merk33gt1hnl6pvbu71",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "site_id": "site_3merk33gt21kym11een1",
      "name": "string",
      "actions": [
        {
          "id": "open",
          "name": "Open"
        }
      ],
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Get gadget

GET /gadgets/{gadget_id}
gadget_id
in path
string (gadget_id)

gadget ID

An instance of gadget
Response Example (200 OK)
{
  "id": "gad_3merk33gt1hnl6pvbu71",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "site_id": "site_3merk33gt21kym11een1",
  "name": "string",
  "actions": [
    {
      "id": "open",
      "name": "Open"
    }
  ],
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit gadget

PATCH /gadgets/{gadget_id}
gadget_id
in path
string (gadget_id)

gadget ID

metadata
metadata

Key-value metadata

Request Example
{
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of gadget
Response Example (200 OK)
{
  "id": "gad_3merk33gt1hnl6pvbu71",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "site_id": "site_3merk33gt21kym11een1",
  "name": "string",
  "actions": [
    {
      "id": "open",
      "name": "Open"
    }
  ],
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Do gadget action

POST /gadgets/{gadget_id}/actions/{action_id}
gadget_id
in path
string (gadget_id)

gadget ID

action_id
in path
string

gadget action ID

Request Example
"object"
Response Example (200 OK)
"object"

Members

member

id
string (member_id)

member ID

organization_id
string (organization_id)

organization ID

name
string

Member name shown in the admin panel. This is for the organization admins to identify the member, it's never shown to the user.

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "mem_3merk33gt7ml3tde71f3",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

member_email

id
string (member_email_id)

member email ID

organization_id
string (organization_id)

organization ID

member_id
string (member_id)

member ID

email
string (email_address)

Email address

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "me_3rkd7ya2pnjysjqbluj1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "email": "hello@example.com",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

member_group_association

id
string (member_group_association_id)

member group association ID

organization_id
string (organization_id)

organization ID

member_id
string (member_id)

member ID

member_group_id
string (member_group_id)

member_group ID

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "mga_3rkd81x2hc3qluv56pl1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List members

GET /members
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
member
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "mem_3merk33gt7ml3tde71f3",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "name": "John Doe",
      "starts_at": "2018-03-13T16:56:51.766836837Z",
      "ends_at": "2018-03-13T16:56:51.766836837Z",
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Create member

POST /members
name
string

Member name shown in the admin panel. This is for the organization admins to identify the member, it's never shown to the user.

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

metadata
metadata

Key-value metadata

Request Example
{
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member
Response Example (200 OK)
{
  "id": "mem_3merk33gt7ml3tde71f3",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Get member

GET /members/{member_id}
member_id
in path
string (member_id)

member ID

An instance of member
Response Example (200 OK)
{
  "id": "mem_3merk33gt7ml3tde71f3",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit member

PATCH /members/{member_id}
member_id
in path
string (member_id)

member ID

name
string

Member name shown in the admin panel. This is for the organization admins to identify the member, it's never shown to the user.

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

metadata
metadata

Key-value metadata

Request Example
{
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member
Response Example (200 OK)
{
  "id": "mem_3merk33gt7ml3tde71f3",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Delete member

DELETE /members/{member_id}
member_id
in path
string (member_id)

member ID

An instance of member
Response Example (200 OK)
{
  "id": "mem_3merk33gt7ml3tde71f3",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "John Doe",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List emails

GET /members/{member_id}/emails
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

member_id
in path
string (member_id)

member ID

data
member_email
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "me_3rkd7ya2pnjysjqbluj1",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "member_id": "mem_3merk33gt7ml3tde71f3",
      "email": "hello@example.com",
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Create email

POST /members/{member_id}/emails
member_id
in path
string (member_id)

member ID

email
string (email)

Email address

metadata
metadata

Key-value metadata

Request Example
{
  "email": "string (email)",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member_email
Response Example (200 OK)
{
  "id": "me_3rkd7ya2pnjysjqbluj1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "email": "hello@example.com",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Get email

GET /members/{member_id}/emails/{member_email_id}
member_id
in path
string (member_id)

member ID

member_email_id
in path
string (member_email_id)

member email ID

An instance of member_email
Response Example (200 OK)
{
  "id": "me_3rkd7ya2pnjysjqbluj1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "email": "hello@example.com",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit email

PATCH /members/{member_id}/emails/{member_email_id}
member_id
in path
string (member_id)

member ID

member_email_id
in path
string (member_email_id)

member email ID

metadata
metadata

Key-value metadata

Request Example
{
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member_email
Response Example (200 OK)
{
  "id": "me_3rkd7ya2pnjysjqbluj1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "email": "hello@example.com",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Delete email

DELETE /members/{member_id}/emails/{member_email_id}
member_id
in path
string (member_id)

member ID

member_email_id
in path
string (member_email_id)

member email ID

An instance of member_email
Response Example (200 OK)
{
  "id": "me_3rkd7ya2pnjysjqbluj1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "email": "hello@example.com",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List group associations

GET /members/{member_id}/group_associations
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

member_id
in path
string (member_id)

member ID

data
member_group_association
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "mga_3rkd81x2hc3qluv56pl1",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "member_id": "mem_3merk33gt7ml3tde71f3",
      "member_group_id": "mg_3merk33gt1692dk2p2m1",
      "starts_at": "2018-03-13T16:56:51.766836837Z",
      "ends_at": "2018-03-13T16:56:51.766836837Z",
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Create group association

POST /members/{member_id}/group_associations
member_id
in path
string (member_id)

member ID

member_group_id
string (member_group_id)

member_group ID

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

metadata
metadata

Key-value metadata

Request Example
{
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member_group_association
Response Example (200 OK)
{
  "id": "mga_3rkd81x2hc3qluv56pl1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Get group association

GET /members/{member_id}/group_associations/{member_group_association_id}
member_id
in path
string (member_id)

member ID

member_group_association_id
in path
string (member_group_association_id)

member group association ID

An instance of member_group_association
Response Example (200 OK)
{
  "id": "mga_3rkd81x2hc3qluv56pl1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit group association

PATCH /members/{member_id}/group_associations/{member_group_association_id}
member_id
in path
string (member_id)

member ID

member_group_association_id
in path
string (member_group_association_id)

member group association ID

starts_at
string (date-time)

Start date of the member's access. If null, the access is valid immediately.

ends_at
string (date-time)

End date of the member's access. If null, the access is valid forever (ie, until an end date is set or the member is deleted.)

metadata
metadata

Key-value metadata

Request Example
{
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member_group_association
Response Example (200 OK)
{
  "id": "mga_3rkd81x2hc3qluv56pl1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Delete group association

DELETE /members/{member_id}/group_associations/{member_group_association_id}
member_id
in path
string (member_id)

member ID

member_group_association_id
in path
string (member_group_association_id)

member group association ID

An instance of member_group_association
Response Example (200 OK)
{
  "id": "mga_3rkd81x2hc3qluv56pl1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "member_id": "mem_3merk33gt7ml3tde71f3",
  "member_group_id": "mg_3merk33gt1692dk2p2m1",
  "starts_at": "2018-03-13T16:56:51.766836837Z",
  "ends_at": "2018-03-13T16:56:51.766836837Z",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Member groups

member_group

id
string (member_group_id)

member_group ID

organization_id
string (organization_id)

organization ID

name
string

Group name

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

metadata
metadata

Key-value metadata

Example
{
  "id": "mg_3merk33gt1692dk2p2m1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "string",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

List member groups

GET /member_groups
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
member_group
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "mg_3merk33gt1692dk2p2m1",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "name": "string",
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z",
      "metadata": {
        "key1": "value1",
        "key2": "value2"
      }
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Get member group

GET /member_groups/{member_group_id}
member_group_id
in path
string (member_group_id)

member_group ID

An instance of member_group
Response Example (200 OK)
{
  "id": "mg_3merk33gt1692dk2p2m1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "string",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Edit member group

PATCH /member_groups/{member_group_id}
member_group_id
in path
string (member_group_id)

member_group ID

metadata
metadata

Key-value metadata

Request Example
{
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}
An instance of member_group
Response Example (200 OK)
{
  "id": "mg_3merk33gt1692dk2p2m1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "name": "string",
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z",
  "metadata": {
    "key1": "value1",
    "key2": "value2"
  }
}

Events

event

id
string (event_id)

event ID

organization_id
string (organization_id)

organization ID

subject
object
verb
string create, edit, delete, use
object
object
created_at
string (date-time)

Creation time for this object.

Example
{
  "id": "evt_3merk33gt21kym11een1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "subject": {
    "type": "member",
    "member_id": "mem_3merk33gt7ml3tde71f3",
    "user_id": "usr_3merk33gt13y99aqtze1",
    "user_session_id": "sess_3merk33gt13y99aqtze1",
    "api_key_id": "ak_3merk33gt21kym11een1",
    "admin_id": "adm_3merk33gt7ml3ltq5bg1"
  },
  "verb": "use",
  "object": {
    "type": "gadget_action",
    "admin_id": "adm_3merk33gt7ml3ltq5bg1",
    "api_key_id": "ak_3merk33gt21kym11een1",
    "device_id": "dev_3merk33gt3l525ryhcmh",
    "gadget_id": "gad_3merk33gt1hnl6pvbu71",
    "link_id": "lnk_3merk33gt345nu3dnkmh",
    "member_id": "mem_3merk33gt7ml3tde71f3",
    "member_group_id": "mg_3merk33gt1692dk2p2m1",
    "member_invitation_id": "mi_3merk33gt7fsymkn47q1",
    "site_id": "site_3merk33gt21kym11een1",
    "gadget_action_id": "open"
  },
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

List events

GET /events
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
event
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "evt_3merk33gt21kym11een1",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "subject": {
        "type": "member",
        "member_id": "mem_3merk33gt7ml3tde71f3",
        "user_id": "usr_3merk33gt13y99aqtze1",
        "user_session_id": "sess_3merk33gt13y99aqtze1",
        "api_key_id": "ak_3merk33gt21kym11een1",
        "admin_id": "adm_3merk33gt7ml3ltq5bg1"
      },
      "verb": "use",
      "object": {
        "type": "gadget_action",
        "admin_id": "adm_3merk33gt7ml3ltq5bg1",
        "api_key_id": "ak_3merk33gt21kym11een1",
        "device_id": "dev_3merk33gt3l525ryhcmh",
        "gadget_id": "gad_3merk33gt1hnl6pvbu71",
        "link_id": "lnk_3merk33gt345nu3dnkmh",
        "member_id": "mem_3merk33gt7ml3tde71f3",
        "member_group_id": "mg_3merk33gt1692dk2p2m1",
        "member_invitation_id": "mi_3merk33gt7fsymkn47q1",
        "site_id": "site_3merk33gt21kym11een1",
        "gadget_action_id": "open"
      },
      "created_at": "2018-03-13T16:56:51.766836837Z"
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Get event

GET /events/{event_id}
event_id
in path
string (event_id)

event ID

An instance of event
Response Example (200 OK)
{
  "id": "evt_3merk33gt21kym11een1",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "subject": {
    "type": "member",
    "member_id": "mem_3merk33gt7ml3tde71f3",
    "user_id": "usr_3merk33gt13y99aqtze1",
    "user_session_id": "sess_3merk33gt13y99aqtze1",
    "api_key_id": "ak_3merk33gt21kym11een1",
    "admin_id": "adm_3merk33gt7ml3ltq5bg1"
  },
  "verb": "use",
  "object": {
    "type": "gadget_action",
    "admin_id": "adm_3merk33gt7ml3ltq5bg1",
    "api_key_id": "ak_3merk33gt21kym11een1",
    "device_id": "dev_3merk33gt3l525ryhcmh",
    "gadget_id": "gad_3merk33gt1hnl6pvbu71",
    "link_id": "lnk_3merk33gt345nu3dnkmh",
    "member_id": "mem_3merk33gt7ml3tde71f3",
    "member_group_id": "mg_3merk33gt1692dk2p2m1",
    "member_invitation_id": "mi_3merk33gt7fsymkn47q1",
    "site_id": "site_3merk33gt21kym11een1",
    "gadget_action_id": "open"
  },
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

Webhooks

webhook_filter_rule

object_type
string gadget, gadget_action, member, member_group, organization, site

Object type of the event.

verb
string create, edit, delete, use

Action verb of the event. If null, matches all verbs.

Example
[
  {
    "object_type": "gadget_action",
    "verb": "use"
  }
]

webhook

id
string (webhook_id)

webhook ID

organization_id
string (organization_id)

organization ID

filter
webhook_filter_rule

Array of event filter rules. An event will be sent to this webhook if it matches at least one rule. If it matches multiple rules, it will only be sent once. If it matches multiple webhook objects, it will be sent once per webhook to its respective URL.

url
string

URL the events are sent to.

secret
string

Secret used to sign webhooks. Visible only in the response for the creation API call.

is_enabled
boolean

True if this webhook is enabled. When false, no webhooks are sent.

is_deleted
boolean

True if this object has been deleted.

created_at
string (date-time)

Creation time for this object.

Example
{
  "id": "string (webhook_id)",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "filter": [
    [
      {
        "object_type": "gadget_action",
        "verb": "use"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
  "is_enabled": false,
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

List webhooks

GET /webhooks
cursor
in query
string

Cursor value obtained from a previous request to the same endpoint. If not present, the first page of results is returned.

limit
in query
number (int32)

Items per page.

data
webhook
has_next
boolean
cursor_next
string (cursor)
Response Example (200 OK)
{
  "data": [
    {
      "id": "string (webhook_id)",
      "organization_id": "org_3merk33gt1v9ypgfzrp1",
      "filter": [
        [
          {
            "object_type": "gadget_action",
            "verb": "use"
          }
        ]
      ],
      "url": "https://example.com/hook",
      "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
      "is_enabled": false,
      "is_deleted": false,
      "created_at": "2018-03-13T16:56:51.766836837Z"
    }
  ],
  "has_next": true,
  "cursor_next": "i9vmCnOgONT2AjUMCn1K1N5cJg=="
}

Create webhook

POST /webhooks
filter
object[]

Array of event filter rules. An event will be sent to this webhook if it matches at least one rule. Null in verb matches all verbs.

url
string

URL the events are sent to.

is_enabled
boolean

True if this webhook is enabled. When false, no webhooks are sent.

Request Example
{
  "filter": [
    [
      {
        "object_type": "gadget_action"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "is_enabled": false
}
An instance of webhook
Response Example (200 OK)
{
  "id": "string (webhook_id)",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "filter": [
    [
      {
        "object_type": "gadget_action",
        "verb": "use"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
  "is_enabled": false,
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

Get webhook

GET /webhooks/{webhook_id}
webhook_id
in path
string (webhook_id)

webhook ID

An instance of webhook
Response Example (200 OK)
{
  "id": "string (webhook_id)",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "filter": [
    [
      {
        "object_type": "gadget_action",
        "verb": "use"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
  "is_enabled": false,
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

Edit webhook

PATCH /webhooks/{webhook_id}
webhook_id
in path
string (webhook_id)

webhook ID

filter
object[]

Array of event filter rules. An event will be sent to this webhook if it matches at least one rule. Null in object_type or verb matches all.

url
string

URL the events are sent to.

is_enabled
boolean

True if this webhook is enabled. When false, no webhooks are sent.

Request Example
{
  "filter": [
    [
      {
        "object_type": "gadget_action"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "is_enabled": false
}
An instance of webhook
Response Example (200 OK)
{
  "id": "string (webhook_id)",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "filter": [
    [
      {
        "object_type": "gadget_action",
        "verb": "use"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
  "is_enabled": false,
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z"
}

Delete webhook

DELETE /webhooks/{webhook_id}
webhook_id
in path
string (webhook_id)

webhook ID

An instance of webhook
Response Example (200 OK)
{
  "id": "string (webhook_id)",
  "organization_id": "org_3merk33gt1v9ypgfzrp1",
  "filter": [
    [
      {
        "object_type": "gadget_action",
        "verb": "use"
      }
    ]
  ],
  "url": "https://example.com/hook",
  "secret": "47f455202923a84cdf8d046e4e1a45b54d6355569e211b388abf389d322db2e4",
  "is_enabled": false,
  "is_deleted": false,
  "created_at": "2018-03-13T16:56:51.766836837Z"
}