---
title: "connect.device@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/connect.device"
updated: null
---

# connect.device@1 · OpenVibe.Services

HTML: [connect.device@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/connect.device)

# ConnectDevice `connect.device@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: connect
- Visibility: public
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/connect/device.v1.json`](/docs/contracts/connect.device.json)

connect.device@1: one device in a private Connect mesh, as its owner sees it. A device belongs to exactly one tenant (the person's own network or a project's), is identified by a Network node principal, and carries only self-reported posture. The mesh control-plane's internal node id, pre-auth key and WireGuard keys are not part of this document.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `id` | string | yes |  | - `pattern ^dev_[0-9A-HJKMNP-TV-Z]{26}$` |
| `owner` | any | yes | The person who owns the device. |  |
| `project_id` | string \| null |  | The project whose mesh the device joins; null for a personal mesh. | - `pattern ^prj_[0-9A-HJKMNP-TV-Z]{26}$` |
| `tenant` | one of | yes | The isolation boundary: one headscale tenant per workspace in v1, never one shared tailnet for all consumer devices. |  |
| `node_id` | string \| null |  | The Network node principal the device presents; null for an agent or server that joins through a pre-auth key. | - `pattern ^lnk_[0-9A-HJKMNP-TV-Z]{26}$` |
| `name` | string | yes | One DNS label in the mesh, shown as name.owner (e.g. pc.alice); never a public hostname. | - `pattern ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$` |
| `status` | enum | yes | pending waits for the owner's approval of a pre-auth join; removed is terminal and its keys are revoked. | - `one of "pending", "online", "offline", "removed"` |
| `os` | enum | yes |  | - `one of "linux", "macos", "windows", "ios", "android", "other"` |
| `arch` | enum |  |  | - `one of "amd64", "arm64", "386", "arm", "other"` |
| `version` | string | yes | The Link release running on the device. | - `minLength 1`<br>- `maxLength 40` |
| `addresses` | array of string |  | The device's private mesh addresses; never a public address. | - `maxItems 8`<br>- `items: minLength 2`<br>- `items: maxLength 64` |
| `tags` | array of string |  |  | - `maxItems 50`<br>- `unique items`<br>- `items: pattern ^[a-z][a-z0-9-]{0,62}$` |
| `posture` | object \| null |  | Self-reported posture, a signal not a guarantee; checked\_at says when it was read. |  |
| `routes` | array of string |  | Subnet routes the device advertises, e.g. 192.168.1.0/24; empty for none. | - `maxItems 50`<br>- `items: minLength 2`<br>- `items: maxLength 64` |
| `exit_node` | boolean |  | Whether the owner allows the device to act as an exit node for this tenant only; never a public proxy. |  |
| `approved_at` | string \| null |  |  | - `format date-time` |
| `approved_by` | any |  | The person who approved the join; null while pending. |  |
| `last_seen_at` | string \| null |  |  | - `format date-time` |
| `expires_at` | string \| null |  | When an unapproved or temporary device stops being valid; null for no expiry. | - `format date-time` |
| `created_at` | string | yes |  | - `format date-time` |
| `updated_at` | string | yes |  | - `format date-time` |
| `revoked_at` | string \| null |  |  | - `format date-time` |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: max-label

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "a-------------------------------------------------------------z",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Valid: one-char

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "a",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Valid: two-char

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "ab",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Valid: workstation

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "workstation",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Rejected: bad-status

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "name": "workstation",
  "status": "connected",
  "os": "linux",
  "version": "0.42.0",
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z"
}
~~~~

Rejected: bad-tenant

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "tenant": {
    "type": "user",
    "id": "team_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "name": "workstation",
  "status": "online",
  "os": "linux",
  "version": "0.42.0",
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z"
}
~~~~

Rejected: leading-hyphen

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "-ab",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Rejected: too-long

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

Rejected: trailing-hyphen

~~~~
{
  "id": "dev_01J8Z3Q4R5S6T7V8W9X0Y1Z2A8",
  "owner": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "project_id": null,
  "tenant": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "node_id": "lnk_01J8Z3Q4R5S6T7V8W9X0Y1Z2A5",
  "name": "ab-",
  "status": "online",
  "os": "linux",
  "arch": "amd64",
  "version": "0.42.0",
  "addresses": [
    "100.64.0.2"
  ],
  "tags": [
    "owner",
    "linux"
  ],
  "posture": {
    "node_current": true,
    "os_patched": true,
    "firewall_on": true,
    "disk_encryption": true,
    "risky_ports": [],
    "checked_at": "2026-10-29T09:00:00.000Z"
  },
  "routes": [],
  "exit_node": false,
  "approved_at": "2026-10-29T08:05:00.000Z",
  "approved_by": {
    "type": "user",
    "id": "usr_01J8Z3Q4R5S6T7V8W9X0Y1Z2A6"
  },
  "last_seen_at": "2026-10-29T09:00:00.000Z",
  "expires_at": null,
  "created_at": "2026-10-29T08:00:00.000Z",
  "updated_at": "2026-10-29T09:00:00.000Z",
  "revoked_at": null
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('connect.device@1', value);   // { valid, errors: [{ path, message }] }
~~~~
