# Device integrations

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## GET /device-integrations/events

**Stream hub events**

`operationId: DeviceIntegrationsController_events`

A **Server-Sent Events** stream of events originating from the org's hubs. The response is an event stream, not JSON — read it incrementally.

Note the org comes from the `orgid` **query parameter** here, since an `EventSource` cannot set headers. `kinds` filters which event types arrive.

#### Signature

```http
GET /device-integrations/events (orgid?: string, hub?: string, kinds?: string) -> The event stream
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Tenant is taken from the query string.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/hubs/live-states`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `hub` | query | string | — |  |
| `kinds` | query | string | — | Comma-separated event kinds. |
| `orgid` | query | string | yes | The org — passed as a query parameter because EventSource cannot send headers. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The event stream |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /device-integrations/hubs/{sk}/api-key

**Generate a hub API key**

`operationId: DeviceIntegrationsController_mintHubApiKey`

Mints — or regenerates — the key a hub uses to connect. **Regenerating immediately invalidates the old key**, so the hub goes offline until it is reconfigured with the new one.

The key is returned once; it cannot be read back afterwards.

#### Signature

```http
POST /device-integrations/hubs/{sk}/api-key (sk: string) -> The new API key — shown once
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Disconnects the hub until it is reconfigured.
- The key is not retrievable later.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/hubs/live-states`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `sk` | path | string | yes | Hub record key. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The new API key — shown once |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /device-integrations/hubs/live-states

**Get live hub states**

`operationId: DeviceIntegrationsController_hubLiveStates`

Which hubs in the org are online right now — the map to check before dispatching to a device.

#### Signature

```http
GET /device-integrations/hubs/live-states () -> Hub states
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/hubs/{hubName}/state`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Hub states |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /device-integrations/hubs/{hubName}/state

**Get a hub's diagnostic state**

`operationId: DeviceIntegrationsController_hubState`

Live diagnostics for one hub — connection, peripherals and recent activity.

#### Signature

```http
GET /device-integrations/hubs/{hubName}/state (hubName: string) -> The hub state
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /device-integrations/hubs/{hubName}/ping`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `hubName` | path | string | yes | Hub name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The hub state |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /device-integrations/hubs/{hubName}/ping

**Ping a hub**

`operationId: DeviceIntegrationsController_pingHub`

Round-trips a message to a hub and reports the latency — proves the hub is genuinely reachable rather than merely last-seen recently.

#### Signature

```http
POST /device-integrations/hubs/{hubName}/ping (hubName: string) -> Latency and result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/hubs/{hubName}/state`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `hubName` | path | string | yes | Hub name. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | Latency and result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /device-integrations/hubs/{hubName}/discover-paths

**Discover device paths on a hub**

`operationId: DeviceIntegrationsController_discoverHubPaths`

Lists the device files the hub can see — serial ports, USB devices. What to read when configuring a peripheral and you need its actual path.

#### Signature

```http
GET /device-integrations/hubs/{hubName}/discover-paths (hubName: string) -> Device paths
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /device-integrations/hubs/{hubName}/endpoints`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `hubName` | path | string | yes | Hub name. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Device paths |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /device-integrations/hubs/{hubName}/endpoints

**Configure a hub peripheral**

`operationId: DeviceIntegrationsController_setHubEndpoints`

Adds or updates a peripheral on a hub remotely. The hub picks up the change without anyone visiting it — which also means a wrong device path silently breaks that peripheral until someone notices.

#### Signature

```http
POST /device-integrations/hubs/{hubName}/endpoints (hubName: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/hubs/{hubName}/discover-paths`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `hubName` | path | string | yes | Hub name. |

### Request body

The peripheral configuration.

```json
{
  "name": "receipt-printer",
  "kind": "escpos",
  "path": "/dev/usb/lp0"
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /device-integrations/adapters

**List device adapters**

`operationId: DeviceIntegrationsController_list`

Every adapter the platform supports — what kinds of device can be driven at all.

#### Signature

```http
GET /device-integrations/adapters () -> Adapters
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /device-integrations/adapters/configured`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Adapters |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /device-integrations/adapters/configured

**List configured adapters**

`operationId: DeviceIntegrationsController_listConfigured`

The adapters actually set up for this org — the list that says what can be called right now.

#### Signature

```http
GET /device-integrations/adapters/configured () -> Configured adapters
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /device-integrations/call`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Configured adapters |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /device-integrations/call

**Dispatch a device call**

`operationId: DeviceIntegrationsController_call`

Sends a command to a physical device — page a guest, print a ticket, open a charger. The target is chosen by whichever of `adapter`, `device`, `servicePoint` or `location` is supplied, most specific first.

This makes hardware do something in the real world; there is no undo for a printed receipt or a triggered pager.

#### Signature

```http
POST /device-integrations/call (adapter?: string, device?: string, servicePoint?: string, location?: string, body) -> The device result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Drives physical hardware.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /device-integrations/page`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `adapter` | query | string | — |  |
| `device` | query | string | — |  |
| `servicePoint` | query | string | — |  |
| `location` | query | string | — |  |

### Request body

The command.

```json
{
  "action": "print",
  "payload": {
    "lines": [
      "Order A7K2M9QX4",
      "Ready for collection"
    ]
  }
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The device result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /device-integrations/page

**Page a guest**

`operationId: DeviceIntegrationsController_page`

Notifies a guest that they are being called — **SMS by default**, or pager hardware where it is configured. Outward-facing: it messages a real person.

#### Signature

```http
POST /device-integrations/page (adapter?: string, device?: string, body) -> The result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Sends a real message.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /checkin/{taskId}/notify`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `adapter` | query | string | — |  |
| `device` | query | string | — |  |

### Request body

Who to page and what to say.

```json
{
  "phone": "+15551234567",
  "message": "Your table is ready."
}
```

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

