---
title: "Polaris API Reference: Devices, Signage & Calendars | Mersive"
canonical: https://www.mersive.com/resources/docs/api
description: "REST reference for the Polaris API: sign in, list devices, read status and occupancy, reboot and sleep rooms, set digital signage, and push calendar events, with request and response examples."
language: en-US
publisher: Mersive Technologies
---

# Polaris API reference

[Try it in Polaris Cloud ↗ (opens in a new tab)](https://app.mersive.com)

Read room state, reboot and sleep devices, set digital signage, and push calendar events for your whole Polaris fleet from your own tools. 28 operations, one base URL, JSON in and out, and the same sign-in you already use for Polaris Cloud.

Running Mersive Solstice Gen 3? That generation has its own [OpenControl API v2 ↗ (opens in a new tab)](https://documentation.mersive.com/content/topics/opencontrolapi_2_0.html), served by each Pod. This page covers Polaris only.

Before you start

## One base URL, one header

Every call goes to the same host. Paths are not versioned. Send JSON with `Content-Type: application/json` and expect JSON back.

```
https://oapi.mersive.com
```

### Who can call it

Any Polaris Cloud user. Sign in with the user’s email and password to get a token, then send it as `Authorization: Bearer <idToken>`. Every organization-scoped call checks that the token’s user is a member of that organization; anyone else gets `403`.

### Finding IDs

Organization and device IDs come from GET /orgs and GET /devices/{orgId}. Digital signage uses a **space** ID, the room record a device belongs to; get it from display information.

### Try before you build

Polaris Cloud has an interactive version of this reference. Open your organization, go to **Tools → Integrations**, and choose **How to query a Mersive device**. Paste a token and run calls against your own rooms.

Tokens are user credentials. Create a dedicated user for each integration, give it only the organizations it needs, and keep the refresh token out of client-side code.

Conventions

## Pagination, jobs, and errors

Three patterns repeat across the fleet-wide calls. Learn them once.

### Pagination

Fleet reads take `limit` (1 to 1000, default 500) and `cursor`. Each page returns `nextCursor`; pass it back as `cursor` until it is `null`. Cursors are opaque and expire if the device they point at is deleted.

### Background jobs

Fleet-wide writes return `202 Accepted` and a `jobId`. Poll the job’s status call every few seconds. Terminal states are `completed`, `partial_failure`, and `failed`; a partial failure lists the IDs that did not take the change.

### Errors

Standard HTTP status codes with a JSON body. `400` is a validation problem with your request, `401` a missing or expired token, `403` an organization you are not a member of, `404` a device, space, event, or job that does not exist. `429` and `503` are retryable.

```
{ "error": "Access denied" }
```

Error bodies carry a short message under `error` (or `message` on some older calls). Match on the status code, not the text.

All operations

## The whole surface on one screen

Grouped by what they touch. Single-device calls take the IDs in the path or body; fleet calls take the organization in the path and page through its devices.

| Method | Path | What it does | Group |
| --- | --- | --- | --- |
| POST | `/` | Sign in | Authentication |
| POST | `/refresh` | Refresh a token | Authentication |
| GET | `/orgs` | List organizations | Organizations and devices |
| GET | `/devices/{orgId}` | List devices | Organizations and devices |
| GET | `/displayinfo/{orgId}/{deviceId}` | Display information | Single device |
| GET | `/deviceinfo/{orgId}/{deviceId}` | Device network information | Single device |
| GET | `/device-status-aggregate/{orgId}` | Status of every device | Single device |
| POST | `/update_device` | Reboot a device | Single device · control |
| POST | `/sleep` | Sleep or wake a device | Single device · control |
| POST | `/apiCommand` | Send a command to the display | Single device · control |
| POST | `/getDigitalSignageUrl` | Get the signage URL | Single room · digital signage |
| POST | `/updateDigitalSignageUrl` | Set the signage URL | Single room · digital signage |
| GET | `/calendaring/events` | List upcoming events | Single device · calendar |
| POST | `/calendaring/event` | Create an event | Single device · calendar |
| GET | `/calendaring/event/{eventId}` | Get one event | Single device · calendar |
| PATCH | `/calendaring/event/{eventId}` | Update an event | Single device · calendar |
| DELETE | `/calendaring/event/{eventId}` | Delete an event | Single device · calendar |
| DELETE | `/calendaring/events` | Delete several events | Single device · calendar |
| GET | `/motionsensor/status/{orgId}/{deviceId}` | Motion sensor status | Single device · occupancy |
| GET | `/device-status/{orgId}` | Device status, paginated | Whole fleet · reads |
| POST | `/deviceinfo/{orgId}` | Device info, many at once | Whole fleet · reads |
| GET | `/calendaring/{orgId}` | Calendar events, paginated | Whole fleet · reads |
| GET | `/calendaring/current-meetings/{orgId}` | Current meetings, paginated | Whole fleet · reads |
| GET | `/motionsensor/status/{orgId}` | Motion sensor status, paginated | Whole fleet · reads |
| POST | `/devices/sleep/{orgId}` | Sleep or wake every device | Whole fleet · jobs |
| GET | `/devices/sleep/{orgId}/{jobId}` | Sleep job status | Whole fleet · jobs |
| POST | `/digital-signage/{orgId}` | Set signage on every room | Whole fleet · jobs |
| GET | `/digital-signage/{orgId}/{jobId}` | Signage job status | Whole fleet · jobs |

Authentication

## Get a token, then refresh it

Sign in with the email and password of a Polaris Cloud user. The token is a JWT that expires after the number of seconds in `expiresIn` (3600 at the time of writing). Use the refresh token to get a new pair without sending the password again. Every response returns a new refresh token; store the latest one.

POST`/`

### Sign in

Exchanges an email and password for a token pair.

**Auth** None.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | Yes | A Polaris Cloud user. Service accounts are not available; most integrations create a dedicated user for this. |
| `password` | string | Yes | That user’s password. |
| `returnSecureToken` | boolean | No | Defaults to `true`. Leave it out. |

#### Example request

```
curl -X POST https://oapi.mersive.com/ \
  -H "Content-Type: application/json" \
  -d '{"email":"integration@example.com","password":"********"}'
```

#### Response

```
{
  "idToken": "eyJhbGciOiJSUzI1NiIs...",
  "refreshToken": "AMf-vBx...",
  "expiresIn": "3600"
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | The password is invalid, or the user has no password (for example, an SSO-only user) |
| `404` | No user with that email |
| `429` | Too many sign-in attempts. Wait, then retry |
| `503` | The authentication service is unavailable. Retry later |

POST`/refresh`

### Refresh a token

Exchanges a refresh token for a fresh token pair. The refresh token rotates, so persist the one in the response.

**Auth** None.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `refreshToken` | string | Yes | The most recent refresh token you received. |

#### Example request

```
curl -X POST https://oapi.mersive.com/refresh \
  -H "Content-Type: application/json" \
  -d '{"refreshToken":"AMf-vBx..."}'
```

#### Response

```
{
  "idToken": "eyJhbGciOiJSUzI1NiIs...",
  "refreshToken": "AMf-vBy...",
  "expiresIn": "3600"
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Missing or malformed refresh token |
| `401` | Expired, invalid, or revoked refresh token, or the user is disabled or deleted. Sign in again |
| `429` | Too many refresh attempts. Wait, then retry |
| `503` | The token service is unavailable. Retry with the same refresh token |

Organizations and devices

## Find your IDs

Every other call needs an organization ID, and most need a device ID. Start here. Organization IDs match the ID in the Polaris Cloud URL after you sign in.

GET`/orgs`

### List organizations

Returns the organizations the signed-in user belongs to.

**Auth** Bearer token.

#### Example request

```
curl https://oapi.mersive.com/orgs \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "organizations": [
    { "id": "org_8f2c", "name": "Example Corp" }
  ]
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |

GET`/devices/{orgId}`

### List devices

Returns every device in an organization, as ID and name only. Use the status and info calls below for anything more.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Example request

```
curl https://oapi.mersive.com/devices/$ORG \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "devices": [
    { "id": "dev_3a91", "name": "Boardroom 4" },
    { "id": "dev_3a92", "name": "Huddle 2B" }
  ]
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

Single device

## Read one room

Three reads for one device: what the display is showing, how it is connected, and the current state of every device at once.

GET`/displayinfo/{orgId}/{deviceId}`

### Display information

What the room display is showing right now: its name, screen key, custom instructions, and state.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl https://oapi.mersive.com/displayinfo/$ORG/$DEVICE \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "externalDeviceId": "MP4A1B2C3D",
  "internalDeviceId": "dev_3a91",
  "displayName": "Boardroom 4",
  "customInstructions": { "enabled": true, "instructions": "Dial 4321 for AV help" },
  "spaceId": "spc_77e1",
  "screenKey": "482913",
  "status": "online",
  "time": "9/30/2026, 2:14:05 PM"
}
```

`externalDeviceId` is the serial number. `spaceId` is the room record the digital signage calls use. `status` is one of `online`, `offline`, `in-use`, `sharing`, `rebooting`, `sleep`.

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device, space, status, or screen key not found |

GET`/deviceinfo/{orgId}/{deviceId}`

### Device network information

Serial number and the network configuration and addresses of each interface.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl https://oapi.mersive.com/deviceinfo/$ORG/$DEVICE \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "deviceDetails": {
    "serialNumber": "MP4A1B2C3D",
    "stunServerEnabled": true,
    "connectionType": {
      "ethernet": {
        "dns1": "10.0.0.2", "dns2": null, "gateway": "10.0.0.1",
        "hostname": "MP4A1B2C3D", "ipType": "IPv4",
        "ipAddress": "10.0.1.88", "macAddress": "00:1A:2B:3C:4D:5E"
      },
      "wifi": { "...": "present only when Wi-Fi is enabled on the device" }
    }
  }
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found, or it has not reported network settings yet |

GET`/device-status-aggregate/{orgId}`

### Status of every device

One call for the whole organization: state, network addresses, temperature, and motion-sensor status per device. Not paginated. For large fleets, prefer the paginated fleet reads below.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Example request

```
curl https://oapi.mersive.com/device-status-aggregate/$ORG \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "deviceStatuses": {
    "dev_3a91": {
      "deviceId": "dev_3a91",
      "connectionType": ["wired"],
      "ethernetIp": "10.0.1.88", "wifiIp": null,
      "ethernetMac": "00:1A:2B:3C:4D:5E", "wifiMac": null,
      "networkStatus": "connected",
      "state": "online",
      "temperature": "41.2",
      "motionSensorStatus": "active",
      "motionSensorTimestamp": 1759241645000
    }
  }
}
```

Fields are present only when the device has reported them. A device with no motion sensor has no `temperature` or `motionSensor*` keys.

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

Single device · control

## Reboot, sleep, and send display commands

These calls change device state. They return as soon as the request is recorded; the device acts on it within its next check-in.

POST`/update_device`

### Reboot a device

Asks a Pod to reboot. Smart TV devices do not support this.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `org_id` | string | Yes | Organization ID. Note the underscore: this call predates the camel-case convention. |
| `device_id` | string | Yes | Device ID. |
| `action` | string | Yes | `reboot`. |
| `value` | boolean | Yes | `true` to reboot. Defaults to `false`, which does nothing. |

#### Example request

```
curl -X POST https://oapi.mersive.com/update_device \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"org_id":"'$ORG'","device_id":"'$DEVICE'","action":"reboot","value":true}'
```

#### Response

```
{ "message": "Operation Successful" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Reboot is not supported for Smart TVs, or the body failed validation |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found |

POST`/sleep`

### Sleep or wake a device

Sets the device’s sleep state and the method it uses to turn the display off and on.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |
| `sleep` | boolean | Yes | `true` to sleep, `false` to wake. Defaults to `false`. |
| `method` | string | Yes | `HDMI_CEC`, `API_COMMANDS`, or `NONE`. Any other value, including leaving it out, is rejected. |
| `displayOn` | string | No | The command the Pod sends to turn the display on. Required when `method` is `API_COMMANDS`. |
| `displayOff` | string | No | The command the Pod sends to turn the display off. Required when `method` is `API_COMMANDS`. |

The method is saved to the device’s power-management settings and stays in effect for scheduled sleep as well. Other power-management settings on the device are left as they are.

#### Example request

```
curl -X POST https://oapi.mersive.com/sleep \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'","sleep":true,"method":"HDMI_CEC"}'
```

#### Response

```
{ "message": "Operation Successful" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid method, or `displayOn`/`displayOff` missing for `API_COMMANDS` |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device or its settings not found |

POST`/apiCommand`

### Send a command to the display

Queues one raw command string for the Pod to send to the display it controls. Use it for displays that take a control protocol over the Pod’s API power method.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |
| `command` | string | Yes | The command string, exactly as the display expects it. |

#### Example request

```
curl -X POST https://oapi.mersive.com/apiCommand \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'","command":"PWR ON"}'
```

#### Response

```
{ "message": "Operation Successful" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | A field is missing |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device or its settings not found |

Single room · digital signage

## Read and set a room’s signage URL

Signage belongs to the space (the room record), not the device. Get the `spaceId` from display information. Both calls are POST and take the organization ID as `tenantId`.

POST`/getDigitalSignageUrl`

### Get the signage URL

Returns the first signage URL configured for a space.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `tenantId` | string | Yes | Organization ID. |
| `spaceId` | string | Yes | Space ID. |
| `userId` | string | Yes | Any non-empty string. Validation requires it; the server records the token’s user instead. |

#### Example request

```
curl -X POST https://oapi.mersive.com/getDigitalSignageUrl \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tenantId":"'$ORG'","spaceId":"spc_77e1","userId":"api"}'
```

#### Response

```
{ "url": "https://signage.example.com/lobby" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | A field is missing |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | No signage URL is set for this space |

POST`/updateDigitalSignageUrl`

### Set the signage URL

Replaces the space’s signage list with one URL and turns signage on or off.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `tenantId` | string | Yes | Organization ID. |
| `spaceId` | string | Yes | Space ID. |
| `digitalSignageEnabled` | boolean | Yes | Whether the display shows signage when idle. |
| `url` | string | Yes | An absolute URL. |
| `userId` | string | Yes | Any non-empty string. See above. |

#### Example request

```
curl -X POST https://oapi.mersive.com/updateDigitalSignageUrl \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tenantId":"'$ORG'","spaceId":"spc_77e1","digitalSignageEnabled":true,"url":"https://signage.example.com/lobby","userId":"api"}'
```

#### Response

```
{ "message": "Digital signage URL updated successfully" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid URL or a missing field |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

Single device · calendar

## Push meetings from your own booking system

If a room is not on Microsoft 365 or Google calendar, you can push its bookings yourself and the display shows them like any other. Turn on the third-party calendar for the device in Polaris Cloud first; every call here returns 400 until you do. Times are ISO 8601.

GET`/calendaring/events`

### List upcoming events

Returns the next three events that have not ended, soonest first.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl "https://oapi.mersive.com/calendaring/events?orgId=$ORG&deviceId=$DEVICE" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
[
  {
    "id": "evt-1042",
    "timeStart": "2026-10-01T15:00:00.000Z",
    "timeEnd": "2026-10-01T15:30:00.000Z",
    "status": "upcoming",
    "subject": "Weekly sync",
    "organizerName": "A. Patel",
    "teamsMeetingLink": null
  }
]
```

`status` is `upcoming`, `start-soon`, or `ongoing`. Ended events are dropped.

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar is not enabled for this device |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found |

POST`/calendaring/event`

### Create an event

Adds one event to the device’s calendar.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |
| `event` | object | Yes | The event, with the fields below. |
| `event.id` | string | Yes | Your identifier for the event. Numbers are accepted and stored as strings. |
| `event.subject` | string | Yes | Meeting title shown on the display. At least 3 characters. |
| `event.organizerName` | string | Yes | Organizer shown on the display. At least 3 characters. |
| `event.startTime` | string | Yes | ISO 8601 date-time. |
| `event.endTime` | string | Yes | ISO 8601 date-time. |
| `event.teamsMeetingLink` | string \| null | No | Join link, if the meeting has one. |

#### Example request

```
curl -X POST https://oapi.mersive.com/calendaring/event \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'","event":{"id":"evt-1042","subject":"Weekly sync","organizerName":"A. Patel","startTime":"2026-10-01T15:00:00Z","endTime":"2026-10-01T15:30:00Z"}}'
```

#### Response

```
{ "message": "Event set successfully", "id": "evt-1042" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar not enabled, or the event failed validation |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found |

GET`/calendaring/event/{eventId}`

### Get one event

Returns a single event by the ID you gave it.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `eventId` | string | Yes | Event ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl "https://oapi.mersive.com/calendaring/event/evt-1042?orgId=$ORG&deviceId=$DEVICE" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "id": "evt-1042",
  "timeStart": "2026-10-01T15:00:00.000Z",
  "timeEnd": "2026-10-01T15:30:00.000Z",
  "status": "upcoming",
  "subject": "Weekly sync",
  "organizerName": "A. Patel",
  "teamsMeetingLink": null
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar not enabled, the event has already ended, or its times are invalid |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Event or device not found |

PATCH`/calendaring/event/{eventId}`

### Update an event

Changes any of the event’s fields. Send only what changes; at least one field is required.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `eventId` | string | Yes | Event ID. |

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |
| `event` | object | Yes | Any subset of the create fields. |

#### Example request

```
curl -X PATCH https://oapi.mersive.com/calendaring/event/evt-1042 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'","event":{"endTime":"2026-10-01T16:00:00Z"}}'
```

#### Response

```
{ "message": "Event updated successfully", "reboot_required": true, "restart_required": true }
```

`reboot_required` and `restart_required` are always `true` and can be ignored; the display picks up the change on its own.

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar not enabled, or the body is empty or invalid |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Event or device not found |

DELETE`/calendaring/event/{eventId}`

### Delete an event

Removes one event.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `eventId` | string | Yes | Event ID. |

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl -X DELETE https://oapi.mersive.com/calendaring/event/evt-1042 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'"}'
```

#### Response

```
{ "message": "Event deleted successfully", "reboot_required": true, "restart_required": true }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar not enabled, or a field is missing |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Event or device not found |

DELETE`/calendaring/events`

### Delete several events

Removes a list of events in one call.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |
| `eventsIds` | string\[\] | Yes | The event IDs to remove. |

#### Example request

```
curl -X DELETE https://oapi.mersive.com/calendaring/events \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"orgId":"'$ORG'","deviceId":"'$DEVICE'","eventsIds":["evt-1042","evt-1043"]}'
```

#### Response

```
{ "message": "Events deleted successfully", "reboot_required": true, "restart_required": true }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Third-party calendar not enabled, or the list is empty |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found |

Single device · occupancy

## Read the motion sensor

Pods with a connected motion sensor report occupancy and ambient temperature. This returns the sensor records on one device.

GET`/motionsensor/status/{orgId}/{deviceId}`

### Motion sensor status

Returns one record per motion sensor attached to the device. An empty array means no sensor.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `deviceId` | string | Yes | Device ID. |

#### Example request

```
curl https://oapi.mersive.com/motionsensor/status/$ORG/$DEVICE \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
[
  {
    "name": "Motion sensor",
    "type": ["motion_sensor"],
    "status": "active",
    "tooltipInfo": "",
    "timestamp": 1759241645000,
    "eventType": "MotionDetected",
    "description": "",
    "messageId": "m-9f1",
    "temp": "41.2",
    "cur_state": "pr01",
    "count_pr": 12, "count_pr00": 5, "count_pr01": 7,
    "last_update": 1759241645, "current_time": 1759241650
  }
]
```

`status` is `active` (motion recently detected) or `inactive`. `timestamp` is Unix milliseconds. The `count_*`, `cur_state`, and `last_update` fields are raw sensor counters.

#### Errors

| Status | Meaning |
| --- | --- |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Device not found |

Whole fleet · reads

## Page through every device

Each of these returns one page of devices and a `nextCursor`. Pass the cursor back as the `cursor` query parameter until it comes back `null`. Pages are keyed by device ID.

GET`/device-status/{orgId}`

### Device status, paginated

State, firmware version, and network addresses for every device.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | Page size, 1 to 1000. Defaults to 500. |
| `cursor` | string | No | The `nextCursor` value from the previous page. Treat it as opaque. |

#### Example request

```
curl "https://oapi.mersive.com/device-status/$ORG?limit=500" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "devices": {
    "dev_3a91": {
      "state": "online",
      "firmwareVersion": "18.1.0",
      "connectionType": ["wired"],
      "networkStatus": "connected",
      "ethernetIp": "10.0.1.88", "wifiIp": null,
      "ethernetMac": "00:1A:2B:3C:4D:5E", "wifiMac": null
    },
    "dev_3a92": null
  },
  "nextCursor": "organizations/org_8f2c/devices/dev_3a92"
}
```

A `null` record is a device that has never reported status.

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

POST`/deviceinfo/{orgId}`

### Device info, many at once

The device-information read for many devices in one call. Send `deviceIds` for a specific set, or send no body to page through every device. POST because the gateway does not allow a body on GET.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | Page size, 1 to 500. Defaults to 500. Lower than the other fleet reads because each device costs four reads. |
| `cursor` | string | No | The `nextCursor` value from the previous page. Treat it as opaque. |

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `deviceIds` | string\[\] | No | Up to 500 device IDs. Omit the body, or send an empty object, to page through all devices with `limit` and `cursor`. |

#### Example request

```
curl -X POST "https://oapi.mersive.com/deviceinfo/$ORG" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"deviceIds":["dev_3a91","dev_0000"]}'
```

#### Response

```
{
  "devices": [
    {
      "id": "dev_3a91", "name": "Boardroom 4", "orgId": "org_8f2c",
      "status": "online", "lastSeen": "2026-09-30T20:14:05.000Z",
      "ipAddress": "10.0.1.88", "firmwareVersion": "18.1.0",
      "model": "Polaris Pro", "serialNumber": "MP4A1B2C3D",
      "properties": {
        "stunServerEnabled": true,
        "connectionType": { "ethernet": { "...": "as in the single-device read" } }
      }
    }
  ],
  "notFound": ["dev_0000"],
  "nextCursor": null
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `403` | No access to this organization |

GET`/calendaring/{orgId}`

### Calendar events, paginated

Events across every device, optionally limited to a time window.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `timeStart` | string | No | ISO 8601 with offset. Events ending before this are excluded. |
| `timeEnd` | string | No | ISO 8601 with offset. Must be after `timeStart`. |
| `limit` | integer | No | Page size, 1 to 1000. Defaults to 500. |
| `cursor` | string | No | The `nextCursor` value from the previous page. Treat it as opaque. |

#### Example request

```
curl "https://oapi.mersive.com/calendaring/$ORG?timeStart=2026-10-01T00:00:00-06:00&timeEnd=2026-10-02T00:00:00-06:00" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "events": [
    {
      "id": "evt-1042", "deviceId": "dev_3a91",
      "timeStart": "2026-10-01T15:00:00.000Z", "timeEnd": "2026-10-01T15:30:00.000Z",
      "status": "upcoming", "subject": "Weekly sync",
      "organizerName": "A. Patel", "teamsMeetingLink": null
    }
  ],
  "nextCursor": null
}
```

Unlike the single-device list, this includes `ended` events inside the window.

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

GET`/calendaring/current-meetings/{orgId}`

### Current meetings, paginated

For each device: the meeting happening now, the one before it, and the one after.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | Page size, 1 to 1000. Defaults to 500. |
| `cursor` | string | No | The `nextCursor` value from the previous page. Treat it as opaque. |

#### Example request

```
curl "https://oapi.mersive.com/calendaring/current-meetings/$ORG" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "devices": {
    "dev_3a91": {
      "current": {
        "id": "evt-1042",
        "timeStart": "2026-10-01T15:00:00.000Z",
        "timeEnd": "2026-10-01T15:30:00.000Z",
        "status": "ongoing",
        "subject": "Weekly sync",
        "organizerName": "A. Patel",
        "teamsMeetingLink": null
      },
      "previous": null,
      "next": null
    }
  },
  "nextCursor": null
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

GET`/motionsensor/status/{orgId}`

### Motion sensor status, paginated

The motion-sensor record for every device, or `null` where there is no sensor.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Query parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `limit` | integer | No | Page size, 1 to 1000. Defaults to 500. |
| `cursor` | string | No | The `nextCursor` value from the previous page. Treat it as opaque. |

#### Example request

```
curl "https://oapi.mersive.com/motionsensor/status/$ORG" \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "devices": {
    "dev_3a91": { "name": "Motion sensor", "type": ["motion_sensor"], "status": "active", "timestamp": 1759241645000, "temp": "41.2", "...": "same record as the single-device read" },
    "dev_3a92": null
  },
  "nextCursor": null
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

Whole fleet · jobs

## Change every device at once

Fleet-wide changes run as background jobs. The call returns `202 Accepted` with a `jobId`; poll the matching status call until `status` is `completed`, `partial_failure`, or `failed`. Counts are `null` until the job starts.

POST`/devices/sleep/{orgId}`

### Sleep or wake every device

Starts a job that puts every device in the organization to sleep, or wakes them all.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `sleep` | boolean | Yes | `true` to sleep, `false` to wake. |

#### Example request

```
curl -X POST https://oapi.mersive.com/devices/sleep/$ORG \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sleep":true}'
```

#### Response

```
HTTP/1.1 202 Accepted

{ "jobId": "5b8e2d1c-7f3a-4c9e-9d2b-1a6f0e4c8b7d" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

GET`/devices/sleep/{orgId}/{jobId}`

### Sleep job status

Progress of a sleep or wake job.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `jobId` | string | Yes | The ID returned when the job was created. |

#### Example request

```
curl https://oapi.mersive.com/devices/sleep/$ORG/$JOB \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "jobId": "5b8e2d1c-7f3a-4c9e-9d2b-1a6f0e4c8b7d",
  "status": "partial_failure",
  "total": 120,
  "succeeded": 118,
  "failed": 2,
  "failedDeviceIds": ["dev_3a92", "dev_3b10"]
}
```

`status` is `pending`, `processing`, `completed`, `partial_failure`, or `failed`.

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Job not found |

POST`/digital-signage/{orgId}`

### Set signage on every room

Starts a job that sets one signage URL, on or off, for every space in the organization.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |

#### Request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `url` | string | Yes | An absolute URL. |
| `enabled` | boolean | Yes | Whether displays show signage when idle. |

#### Example request

```
curl -X POST https://oapi.mersive.com/digital-signage/$ORG \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://signage.example.com/lobby","enabled":true}'
```

#### Response

```
HTTP/1.1 202 Accepted

{ "jobId": "c2f4a9e1-3d7b-4e8a-b5c6-9f0d1e2a3b4c" }
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |

GET`/digital-signage/{orgId}/{jobId}`

### Signage job status

Progress of a signage job. Failures are reported by space, not device.

**Auth** Bearer token. The token’s user must be a member of the organization named in the request.

#### Path parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `orgId` | string | Yes | Organization ID. |
| `jobId` | string | Yes | The ID returned when the job was created. |

#### Example request

```
curl https://oapi.mersive.com/digital-signage/$ORG/$JOB \
  -H "Authorization: Bearer $TOKEN"
```

#### Response

```
{
  "jobId": "c2f4a9e1-3d7b-4e8a-b5c6-9f0d1e2a3b4c",
  "status": "completed",
  "total": 120,
  "succeeded": 120,
  "failed": 0,
  "failedSpaceIds": []
}
```

#### Errors

| Status | Meaning |
| --- | --- |
| `400` | Invalid parameters |
| `401` | Missing or invalid token |
| `403` | The token’s user is not a member of this organization |
| `404` | Job not found |

Good to know

## Behavior that is easy to miss

- **Writes are acknowledged, not confirmed.** Reboot, sleep, signage, and command calls return once the request is saved. The device acts on it at its next check-in, normally within seconds. Read device status afterwards to confirm.
- **Two naming styles.** `POST /update_device` takes `org_id` and `device_id`; everything newer is camel case. Both are supported and neither is going away.
- **Signage calls are POST, even the read.** `/getDigitalSignageUrl` takes a JSON body. The `userId` field must be present but is not used; the token’s user is recorded instead.
- **The single-device calendar list returns three events.** Use the paginated fleet calendar read with a time window when you need more.
- **Tokens expire in an hour.** Refresh proactively rather than on `401`, and always store the refresh token from the latest response.

Found a difference between this page and what the API returns? [Tell us](https://www.mersive.com/contact). The reference is generated from the same schemas the service validates with, but the service is the source of truth.
