# devices (/docs/reference/api/devices)

> Device posture tells policies which registered device a request comes from and whether an MDM or EDR finds it compliant.



Device posture tells policies which registered device a request comes from and whether an MDM or EDR finds it
compliant. A browser or agent enrolls a public key once, then sends a short-lived signed proof with its requests in
the `x-better-iam-device` header. The proof is bound to the session it travels with. Decisions check it against the
enrolled key and expose `request.deviceAssurance`, `request.deviceManaged`, `request.deviceCompliant`,
`request.deviceId` and `request.devicePlatform`. Integrations report the devices they manage and their posture, and
the tenant's requirements decide which of them are compliant. Registered devices are not remembered devices
("remember this device" at sign-in): they never satisfy MFA. The guide is
[Device posture](https://github.com/Better-IAM/better-iam/blob/main/docs/device-posture.md), and the browser and Node
helper is `@better-iam/client/device`.

## Assurance levels [#assurance-levels]

Every request gets one level, weakest first:

* `none`: no proof, or one that did not verify. A bad proof is never an error.
* `registered`: a verified proof from an active device that no active integration manages.
* `managed`: the device is reported by an active integration but misses a requirement.
* `compliant`: a managed device that meets every requirement of the tenant (see [configure](#configure)).

A proof is a compact JWS whose protected header holds only `alg`, `typ` (`device-proof+jwt`) and `kid` (the RFC 7638
thumbprint of an enrolled key), with `iat` within 300 seconds of the server clock and `sid` equal to the id of the
session that authenticated the request. The algorithm is pinned by the stored key (`ES256` for EC P-256, `EdDSA` for
Ed25519), and a header carrying key material (`jwk`, `jku`, `x5u`, `x5c`) or `crit` is refused. The device must be
active, in the identity's home tenant, and shared or owned by the identity.

## Who may call what [#who-may-call-what]

People manage their own devices without a permission: `enroll`, `mine` and `retireMine` from their own sign-in session
or API key in the tenant, and `check` from any session of the tenant. Administrators hold `iam:devices:read` or
`iam:devices:manage` on `iam/devices`, `iam/devices/{id}`, `iam/devices/enrollments`, `iam/devices/settings` and
`iam/devices/integrations/{id}`. Every `iam:devices:manage` call except `listEnrollments` and `revokeEnrollment`
needs a recent sign-in. Integrations call `report` with `iam:devices:report` on their own
`iam/devices/integrations/{id}`, usually through a service account's API key.

| Method                                    | What it does                                                                                                                          | Access     |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| [`check`](#check)                         | Reports what the device presenting this request proves: its assurance, id, platform and compliance.                                   | Credential |
| [`configure`](#configure)                 | Sets the requirements a managed device must meet to be compliant.                                                                     | Credential |
| [`createEnrollment`](#createenrollment)   | Creates a one-time enrollment code that binds a browser or agent key to a device, usually one an integration manages.                 | Credential |
| [`createIntegration`](#createintegration) | Adds an MDM or EDR integration that can report devices and their posture.                                                             | Credential |
| [`delete`](#delete)                       | Deletes a device with its keys and enrollment codes.                                                                                  | Credential |
| [`deleteIntegration`](#deleteintegration) | Deletes an integration, optionally leaving the devices it manages unmanaged.                                                          | Credential |
| [`enroll`](#enroll)                       | Enrolls a public key for the caller's browser or agent, creating their device or binding the key to a device with an enrollment code. | Credential |
| [`get`](#get)                             | Returns one device with its enrolled keys.                                                                                            | Credential |
| [`getSettings`](#getsettings)             | Returns the tenant's compliance requirements, or the defaults until they are configured.                                              | Credential |
| [`list`](#list)                           | Lists the tenant's devices, newest first, each with its compliance, assurance, key count and owner.                                   | Credential |
| [`listEnrollments`](#listenrollments)     | Lists the tenant's enrollment codes, newest first, without the codes themselves.                                                      | Credential |
| [`listIntegrations`](#listintegrations)   | Lists the tenant's MDM and EDR integrations by name, with the number of devices each manages.                                         | Credential |
| [`mine`](#mine)                           | Lists the caller's devices that are not retired, each with its compliance and assurance, the device presenting this request first.    | Credential |
| [`removeKey`](#removekey)                 | Removes one enrolled key from a device, such as a lost browser profile or a replaced agent.                                           | Credential |
| [`report`](#report)                       | Creates or updates up to 500 devices with their posture, as reported by an integration, all or nothing.                               | Credential |
| [`retire`](#retire)                       | Retires a device for good, deleting its keys and pending enrollment codes.                                                            | Credential |
| [`retireMine`](#retiremine)               | Retires one of the caller's own unmanaged devices and deletes its keys.                                                               | Credential |
| [`revokeEnrollment`](#revokeenrollment)   | Withdraws an enrollment code, used or not.                                                                                            | Credential |
| [`update`](#update)                       | Renames a device, changes its owner, or marks it lost or active again.                                                                | Credential |
| [`updateIntegration`](#updateintegration) | Renames an integration, disables or enables it, or changes whether the vendor's verdict counts.                                       | Credential |

## check [#check]

Reports what the device presenting this request proves: its assurance, id, platform and compliance.

**HTTP:** `POST /api/iam/devices/check` (requires a credential) · **Browser client:** `client.devices.check()`

* **Permission:** Any session of the tenant.
* **Audited as:** Not audited. It records when the device and key were last seen, at most once a minute.
* **Errors:** `ACCESS_DENIED` for a session of another tenant.

`proof` is `absent` (no header), `invalid` (the proof did not verify: an unknown or removed key, another session, a
clock more than five minutes off, a lost or retired device) or `verified`. For a verified device `reasons` explains
why it is not compliant (`not-managed`, `stale`, `not-encrypted`, `os-too-old` and so on). Call it after sign-in to
decide whether to offer enrollment.

```ts
const status = await client.devices.check({ tenantId });
// { assurance: 'registered', deviceId, platform: 'macos', managed: false, compliant: false,
//   reasons: ['not-managed'], proof: 'verified' }
```

```ts title="Signature"
iam.api.devices.check(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<DeviceCheck>
```

## configure [#configure]

Sets the requirements a managed device must meet to be compliant.

**HTTP:** `POST /api/iam/devices/configure` (requires a credential) · **Browser client:** `client.devices.configure()`

* **Permission:** `iam:devices:manage` on `iam/devices/settings`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:settings` with the requirements before and after.
* **Errors:** `INVALID_INPUT` for an unknown field, a flag that is not a boolean, an unknown platform or a minimum that
  is not a dotted version in `minOsVersions`, or a `maxCheckInAgeHours` outside 1 to 720; `RECENT_AUTH_REQUIRED`.

`requireEncrypted`, `requireScreenLock`, `requireFirewall` and `requireEdr` need the posture field reported `true`
(unknown fails). `blockJailbroken` (on by default) fails a device reported jailbroken. `minOsVersions` sets a minimum
per platform (a device with an unknown version then fails), and `maxCheckInAgeHours` (24 by default) fails devices
whose last check-in is older. An integration with `trustVendorCompliance` also fails devices its vendor calls
non-compliant. Fields left out keep their values; `minOsVersions` replaces the whole map. Compliance is worked out at
decision time, so the new requirements apply to the next request.

```ts
await iam.api.devices.configure(credential, {
  tenantId,
  requireEncrypted: true,
  requireScreenLock: true,
  minOsVersions: { macos: '14.0', windows: '10.0.19045' },
  maxCheckInAgeHours: 12,
});
```

```ts title="Signature"
iam.api.devices.configure(
  credential: CredentialInput,
  input: {
    tenantId: string;
    requireEncrypted?: boolean;
    requireScreenLock?: boolean;
    requireFirewall?: boolean;
    requireEdr?: boolean;
    blockJailbroken?: boolean;
    minOsVersions?: Partial<Record<DevicePlatform, string>>;
    maxCheckInAgeHours?: number;
  },
): Promise<DeviceSettingsView>
```

## createEnrollment [#createenrollment]

Creates a one-time enrollment code that binds a browser or agent key to a device, usually one an integration manages.

**HTTP:** `POST /api/iam/devices/createEnrollment` (requires a credential) · **Browser client:** `client.devices.createEnrollment()`

* **Permission:** `iam:devices:manage` on `iam/devices/enrollments` (and, with `deviceId`, on `iam/devices/{id}` too,
  since using the code adds a key to that device), and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:enrollment-create` (never the code).
* **Errors:** `ACCESS_DENIED` without `iam:devices:manage` on the device named by `deviceId`; `INVALID_INPUT` for an
  `expiresInMs` outside 10 minutes to 30 days, an owner who is not a person of the
  tenant, or an owner other than the device's; `INVALID_TRANSITION` (409) when the device is not active;
  `LIMIT_EXCEEDED` (409) past 1000 pending codes in the tenant; `NOT_FOUND` for a device outside the tenant;
  `RECENT_AUTH_REQUIRED`.

The code (`biam_denr_…`) appears only in this answer and is stored as a hash. It lasts 7 days unless `expiresInMs`
says otherwise and works once. With `deviceId`, enrollment binds the key to that device; a device with an owner limits
the code to that person, as `ownerIdentityId` does. Deliver the code to the machine through the MDM, where the app
passes it to [`enroll`](#enroll) after the person signs in.

```ts
const { code, expiresAt, enrollmentId } = await iam.api.devices.createEnrollment(credential, {
  tenantId,
  deviceId: managedDeviceId,
  ownerIdentityId: aliceId,
  expiresInMs: 24 * 3_600_000,
});
```

```ts title="Signature"
iam.api.devices.createEnrollment(
  credential: CredentialInput,
  input: {
    tenantId: string;
    deviceId?: string;
    ownerIdentityId?: string;
    expiresInMs?: number;
  },
): Promise<DeviceEnrollmentCode>
```

## createIntegration [#createintegration]

Adds an MDM or EDR integration that can report devices and their posture.

**HTTP:** `POST /api/iam/devices/createIntegration` (requires a credential) · **Browser client:** `client.devices.createIntegration()`

* **Permission:** `iam:devices:manage` on `iam/devices/integrations`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:integration-create`.
* **Errors:** `INVALID_INPUT` for an unknown vendor or field; `CONFLICT` (409) for a name in use (ignoring case);
  `LIMIT_EXCEEDED` (409) past 20 integrations; `RECENT_AUTH_REQUIRED`.

`vendor` is `intune`, `jamf`, `kandji`, `workspace-one`, `google-endpoint`, `crowdstrike`, `sentinelone` or `custom`.
`trustVendorCompliance` (default true) counts the vendor's own verdict next to the tenant's requirements. Give the
connector a service account allowed `iam:devices:report` on `iam/devices/integrations/{id}` for the new id, and an API
key scoped to that action.

```ts title="Signature"
iam.api.devices.createIntegration(
  credential: CredentialInput,
  input: {
    tenantId: string;
    name: string;
    vendor: DeviceIntegrationVendor;
    trustVendorCompliance?: boolean;
  },
): Promise<DeviceIntegrationView>
```

## delete [#delete]

Deletes a device with its keys and enrollment codes.

**HTTP:** `POST /api/iam/devices/delete` (requires a credential) · **Browser client:** `client.devices.delete()`

* **Permission:** `iam:devices:manage` on `iam/devices/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:delete`.
* **Errors:** `RECENT_AUTH_REQUIRED`; `NOT_FOUND`.

A managed device comes back with the integration's next report, as a new record without keys. Use `retire` to keep it
out.

```ts title="Signature"
iam.api.devices.delete(
  credential: CredentialInput,
  input: { tenantId: string; deviceId: string },
): Promise<{ success: true; keysRemoved: number; enrollmentsRemoved: number }>
```

## deleteIntegration [#deleteintegration]

Deletes an integration, optionally leaving the devices it manages unmanaged.

**HTTP:** `POST /api/iam/devices/deleteIntegration` (requires a credential) · **Browser client:** `client.devices.deleteIntegration()`

* **Permission:** `iam:devices:manage` on `iam/devices/integrations/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:integration-delete` with the number of devices detached.
* **Errors:** `RESOURCE_IN_USE` (409) while it manages devices, unless `detach: true`; `NOT_FOUND`;
  `RECENT_AUTH_REQUIRED`.

Detached devices keep their keys and last posture but no longer count as managed, so they drop to `registered`.

```ts title="Signature"
iam.api.devices.deleteIntegration(
  credential: CredentialInput,
  input: { tenantId: string; integrationId: string; detach?: boolean },
): Promise<{ success: true; detached: number }>
```

## enroll [#enroll]

Enrolls a public key for the caller's browser or agent, creating their device or binding the key to a device with an enrollment code.

**HTTP:** `POST /api/iam/devices/enroll` (requires a credential) · **Browser client:** `client.devices.enroll()`

* **Permission:** None beyond a person's own sign-in session or API key in the tenant, with a recent sign-in; never
  while impersonating. The request must carry a device proof (`x-better-iam-device`) signed with the key being
  enrolled, for this session, which proves the caller holds the key.
* **Audited as:** `device:enroll`.
* **Errors:** `INVALID_INPUT` for a key that is not a public EC P-256 or Ed25519 JWK (private members are refused
  outright), a missing proof or one not made with the key for this session, an unknown platform, an invalid, used or
  expired enrollment code, or a caller that is not a person; `CONFLICT` (409) when the key is already enrolled;
  `ACCESS_DENIED` from another kind of session or another tenant, or with a code or device that belongs to someone
  else; `IMPERSONATION_RESTRICTED`; `RECENT_AUTH_REQUIRED`; `LIMIT_EXCEEDED` (409) past 20 devices per person or 20
  keys per device; `INVALID_TRANSITION` (409) when the code's device is not active; `RATE_LIMITED` after 30 attempts
  by one person in a rate-limit window.

Without `enrollmentCode` the call registers a new unmanaged device owned by the caller. With a code from
[`createEnrollment`](#createenrollment) it binds the key to the code's device (then `name` and `platform` are
ignored) or, when the code names no device, creates one owned by the code's person, or shared when the code names
nobody. The code is used up. `keyId` is the key's thumbprint, the `kid` of its proofs. The result's device has
`current: true` when this request already carries a valid proof from it.

```ts
import { createDeviceProver } from 'better-iam/client/device';

const prover = createDeviceProver();
const { device, keyId } = await client.devices.enroll({
  tenantId,
  name: 'Work laptop',
  platform: 'macos',
  publicKey: await prover.publicJwk(),
});
```

```ts title="Signature"
iam.api.devices.enroll(
  credential: CredentialInput,
  input: DeviceEnrollInput,
): Promise<{ device: MyDevice; keyId: string }>
```

## get [#get]

Returns one device with its enrolled keys.

**HTTP:** `POST /api/iam/devices/get` (requires a credential) · **Browser client:** `client.devices.get()`

* **Permission:** `iam:devices:read` on `iam/devices/{id}`.
* **Audited as:** `iam:devices:read`.
* **Errors:** `NOT_FOUND` when the device is not in this tenant.

`publicKeys` lists each key's thumbprint, algorithm (`ES256` or `EdDSA`), who enrolled it and when, and when a
verified proof from it was last seen.

```ts title="Signature"
iam.api.devices.get(
  credential: CredentialInput,
  input: { tenantId: string; deviceId: string },
): Promise<DeviceDetail>
```

## getSettings [#getsettings]

Returns the tenant's compliance requirements, or the defaults until they are configured.

**HTTP:** `POST /api/iam/devices/getSettings` (requires a credential) · **Browser client:** `client.devices.getSettings()`

* **Permission:** `iam:devices:read` on `iam/devices/settings`.
* **Audited as:** `iam:devices:read`.

`configured` is false while the tenant uses the defaults: nothing required except that jailbroken devices fail, and a
check-in within 24 hours.

```ts title="Signature"
iam.api.devices.getSettings(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<DeviceSettingsView>
```

## list [#list]

Lists the tenant's devices, newest first, each with its compliance, assurance, key count and owner.

**HTTP:** `POST /api/iam/devices/list` (requires a credential) · **Browser client:** `client.devices.list()`

* **Permission:** `iam:devices:read` on `iam/devices`.
* **Audited as:** `iam:devices:read`.
* **Errors:** `INVALID_INPUT` for an unknown status or platform, a `limit` outside 1 to 1000, or an `offset` outside 0
  to 1000000.

Filter by `ownerIdentityId`, `status`, `platform`, `managed` and `compliant`, and search with `query` (device id,
name, serial number, model, the integration's device id, and the owner's name or email, case-insensitive). `total`
counts every match before paging. `assurance` is what a proof from the device would get now: `none` while it has no
key or is not active.

```ts title="Signature"
iam.api.devices.list(
  credential: CredentialInput,
  input: {
    tenantId: string;
    ownerIdentityId?: string;
    status?: DeviceStatus;
    managed?: boolean;
    compliant?: boolean;
    platform?: DevicePlatform;
    query?: string;
    limit?: number;
    offset?: number;
  },
): Promise<{ devices: DeviceView[]; total: number }>
```

## listEnrollments [#listenrollments]

Lists the tenant's enrollment codes, newest first, without the codes themselves.

**HTTP:** `POST /api/iam/devices/listEnrollments` (requires a credential) · **Browser client:** `client.devices.listEnrollments()`

* **Permission:** `iam:devices:manage` on `iam/devices/enrollments`.
* **Audited as:** `iam:devices:manage`.

Each entry has its `status` (`pending`, `used` or `expired`), the device and person it is for, and who created and
used it. The retention sweep deletes codes after they expire.

```ts title="Signature"
iam.api.devices.listEnrollments(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<DeviceEnrollmentView[]>
```

## listIntegrations [#listintegrations]

Lists the tenant's MDM and EDR integrations by name, with the number of devices each manages.

**HTTP:** `POST /api/iam/devices/listIntegrations` (requires a credential) · **Browser client:** `client.devices.listIntegrations()`

* **Permission:** `iam:devices:read` on `iam/devices/integrations`.
* **Audited as:** `iam:devices:read`.

```ts title="Signature"
iam.api.devices.listIntegrations(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<DeviceIntegrationView[]>
```

## mine [#mine]

Lists the caller's devices that are not retired, each with its compliance and assurance, the device presenting this request first.

**HTTP:** `POST /api/iam/devices/mine` (requires a credential) · **Browser client:** `client.devices.mine()`

* **Permission:** None beyond a person's own sign-in session or API key in the tenant; also while impersonating.
* **Audited as:** Not audited; it only reads.
* **Errors:** `ACCESS_DENIED` from a role session, session token, delegated session, or a session of another tenant.

`current` marks the device whose proof this request carries. Use it for a "your devices" page.

```ts title="Signature"
iam.api.devices.mine(
  credential: CredentialInput,
  input: { tenantId: string },
): Promise<MyDevice[]>
```

## removeKey [#removekey]

Removes one enrolled key from a device, such as a lost browser profile or a replaced agent.

**HTTP:** `POST /api/iam/devices/removeKey` (requires a credential) · **Browser client:** `client.devices.removeKey()`

* **Permission:** `iam:devices:manage` on `iam/devices/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:key-remove`.
* **Errors:** `NOT_FOUND` when the key is not enrolled on that device; `RECENT_AUTH_REQUIRED`.

```ts title="Signature"
iam.api.devices.removeKey(
  credential: CredentialInput,
  input: { tenantId: string; deviceId: string; keyId: string },
): Promise<{ success: true }>
```

## report [#report]

Creates or updates up to 500 devices with their posture, as reported by an integration, all or nothing.

**HTTP:** `POST /api/iam/devices/report` (requires a credential) · **Browser client:** `client.devices.report()`

* **Permission:** `iam:devices:report` on `iam/devices/integrations/{id}`; no recent sign-in, so a service account's
  API key can call it.
* **Audited as:** `iam:devices:report`; `device:report` once per call with the counts; and
  `device:compliance-change` for each existing device whose compliance flipped.
* **Errors:** `INVALID_INPUT` for an empty list or more than 500 devices, a missing, malformed or repeated
  `externalId`, an unknown platform or field, a posture value that is not a boolean, an `osVersion` over 64
  characters, a malformed `keyThumbprint`, or a `checkedInAt` more than five minutes ahead; `INVALID_TRANSITION` (409)
  when the integration is disabled; `NOT_FOUND` when the integration is not in this tenant.

Devices are matched by the vendor's `externalId` and created on first sight. `null` and empty strings count as absent.
Each report replaces the device's posture, so a field left out becomes unknown. A named owner (`ownerIdentityId` or
`ownerEmail`, a person of the tenant) is set, an unknown one leaves the device without an owner, and a report that
names none keeps the current one. `osVersion` keeps its leading dotted number (`14.5 (23F79)` reads as `14.5`).
`keyThumbprint` moves a key already enrolled in the tenant onto the reported device, retiring the same person's
self-enrolled record of the machine when that record has no keys left. It moves only from an active device of the
reported owner that is self-enrolled or this integration's own: a key on a lost, shared, or someone else's device, or on
a device another integration manages, stays where it is. Reports older than a device's last check-in are ignored,
identical check-ins are written at most once a minute (always when they change the device's compliance), and reports
never change a device's status. The answer counts `created`, `updated`, `unchanged` and `complianceChanged` devices.

```ts
await iam.api.devices.report(
  { token: reporterKey },
  {
    tenantId,
    integrationId,
    devices: [
      {
        externalId: 'jamf-42',
        name: 'MBP-ALICE',
        platform: 'macos',
        serialNumber: 'C02XYZ123',
        osVersion: '14.5 (23F79)',
        ownerEmail: 'alice@acme.test',
        posture: { compliant: true, encrypted: true, firewall: true, screenLock: true },
      },
    ],
  },
);
```

```ts title="Signature"
iam.api.devices.report(
  credential: CredentialInput,
  input: { tenantId: string; integrationId: string; devices: DeviceReport[] },
): Promise<DeviceReportResult>
```

## retire [#retire]

Retires a device for good, deleting its keys and pending enrollment codes.

**HTTP:** `POST /api/iam/devices/retire` (requires a credential) · **Browser client:** `client.devices.retire()`

* **Permission:** `iam:devices:manage` on `iam/devices/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:retire` with `self: false`.
* **Errors:** `INVALID_TRANSITION` (409) when it is already retired; `RECENT_AUTH_REQUIRED`; `NOT_FOUND`.

A retired device proves nothing, and later integration reports keep it retired.

```ts title="Signature"
iam.api.devices.retire(
  credential: CredentialInput,
  input: { tenantId: string; deviceId: string },
): Promise<DeviceView>
```

## retireMine [#retiremine]

Retires one of the caller's own unmanaged devices and deletes its keys.

**HTTP:** `POST /api/iam/devices/retireMine` (requires a credential) · **Browser client:** `client.devices.retireMine()`

* **Permission:** None beyond a person's own sign-in session or API key in the tenant, with a recent sign-in; never
  while impersonating.
* **Audited as:** `device:retire` with `self: true`.
* **Errors:** `NOT_FOUND` when the device is not the caller's; `INVALID_TRANSITION` (409) for a managed device (an
  administrator retires those) or one already retired; `IMPERSONATION_RESTRICTED`; `RECENT_AUTH_REQUIRED`;
  `ACCESS_DENIED` from another kind of session.

```ts title="Signature"
iam.api.devices.retireMine(
  credential: CredentialInput,
  input: { tenantId: string; deviceId: string },
): Promise<{ success: true; keysRemoved: number }>
```

## revokeEnrollment [#revokeenrollment]

Withdraws an enrollment code, used or not.

**HTTP:** `POST /api/iam/devices/revokeEnrollment` (requires a credential) · **Browser client:** `client.devices.revokeEnrollment()`

* **Permission:** `iam:devices:manage` on `iam/devices/enrollments`.
* **Audited as:** `iam:devices:manage`, plus `device:enrollment-revoke`.
* **Errors:** `NOT_FOUND` when the code is not in this tenant.

```ts title="Signature"
iam.api.devices.revokeEnrollment(
  credential: CredentialInput,
  input: { tenantId: string; enrollmentId: string },
): Promise<{ success: true }>
```

## update [#update]

Renames a device, changes its owner, or marks it lost or active again.

**HTTP:** `POST /api/iam/devices/update` (requires a credential) · **Browser client:** `client.devices.update()`

* **Permission:** `iam:devices:manage` on `iam/devices/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:update` with the name, status and owner before and after.
* **Errors:** `INVALID_INPUT` without a name, owner or status to change, for an unknown field, a status other than
  `active` or `lost`, or an owner who is not a person of the tenant; `INVALID_TRANSITION` (409) for a retired device;
  `RECENT_AUTH_REQUIRED`; `NOT_FOUND`.

`ownerIdentityId: null` makes the device shared, so any member of the tenant may present it. A new owner drops the keys
the previous owner enrolled. A `lost` device proves nothing until it is marked `active` again.

```ts title="Signature"
iam.api.devices.update(
  credential: CredentialInput,
  input: {
    tenantId: string;
    deviceId: string;
    name?: string;
    ownerIdentityId?: string | null;
    status?: 'active' | 'lost';
  },
): Promise<DeviceView>
```

## updateIntegration [#updateintegration]

Renames an integration, disables or enables it, or changes whether the vendor's verdict counts.

**HTTP:** `POST /api/iam/devices/updateIntegration` (requires a credential) · **Browser client:** `client.devices.updateIntegration()`

* **Permission:** `iam:devices:manage` on `iam/devices/integrations/{id}`, and a recent sign-in.
* **Audited as:** `iam:devices:manage`, plus `device:integration-update` with the settings before and after.
* **Errors:** `CONFLICT` (409) for a name in use; `INVALID_INPUT` for a status other than `active` or `disabled`, or
  an unknown field; `NOT_FOUND`; `RECENT_AUTH_REQUIRED`.

While an integration is disabled its devices do not count as managed, and its reports are refused.

```ts title="Signature"
iam.api.devices.updateIntegration(
  credential: CredentialInput,
  input: {
    tenantId: string;
    integrationId: string;
    name?: string;
    status?: 'active' | 'disabled';
    trustVendorCompliance?: boolean;
  },
): Promise<DeviceIntegrationView>
```
