Device-user sessions

Tell Nomid who is using which device when your own app signs its users in, and read every device-user session back.

How it works

Use these endpoints when an app of yours authenticates its own users on a managed device. The app identifies the device by its serial number, for example one passed to it in its managed configuration. When a user signs in, your backend reports the login with that serial number and your own id for the user, and keeps the loginId it gets back. When the user signs out, your backend reports the logout.

The first login of an externalUserId creates a device user with auth EXTERNAL for it. Later logins of the same externalUserId reuse that user, and a userName that differs from its current name renames it. You can also report the login of an existing device user of any auth by its deviceUserId.

GET /device-user-logins returns the company's device-user sessions, newest first: those your system reports and the PIN and SSO logins the Nomid agent reports from the device. loginSource and logoutSource say who reported each half of a session.

A session reported through the API has no expiry in Nomid: it stays open until you report its logout. Each login call records a new session, even when the same user is already logged in on that device.

The API closes only sessions that were reported through the API. A PIN or SSO login on the Nomid agent is closed by the device.

Requirements

  • GET /device-user-logins needs DEVICES_READ, like the other device reads.
  • Reporting device-user logins and logouts (POST /device-user-logins and POST /device-user-logins/logout) needs DEVICES_COMMAND, the permission that sends device commands; a key only gets it together with DEVICES_READ. Device-user sessions have no permission of their own.
  • To report a login, the asset must have a managed device, that is, a device enrolled in Nomid now.
  • The validated key selects the company; requests have no tenant or company parameter. The login and logout endpoints can address every asset of the company.

Endpoints

Paths are relative to the API base URL and need the X-API-Key header.

https://api.nomid.tech/emm/api/v1

MethodEndpointPermissionDescription
GET/device-user-loginsDEVICES_READList device-user sessions, newest first, with optional filters
POST/device-user-loginsDEVICES_COMMANDReport that a user your system authenticated logged in on a device; returns 201 with the session
POST/device-user-logins/logoutDEVICES_COMMANDReport a logout, by loginId or by device and user; returns the sessions concerned

List sessions

Every query parameter is optional. Without filters, the endpoint returns the company's latest sessions.

ParameterDescription
assetIdOnly sessions on this asset. Not together with serialNumber.
serialNumberOnly sessions on the asset with this serial number. Not together with assetId.
deviceUserIdOnly sessions of the device user with this Nomid id, deviceUser.id in a session.
externalUserIdOnly sessions of the EXTERNAL device user with this id from your system.
opentrue returns only the sessions still open: not logged out and not expired. Defaults to false, which returns open and closed sessions.
fromOnly sessions that started at or after this ISO-8601 instant, such as 2026-10-01T00:00:00Z.
toOnly sessions that started before this ISO-8601 instant. from must be earlier than to, and both must fall between 1970 and 9999.
limitMaximum number of sessions to return. Defaults to 50; a value above 200 returns 200.

An asset's sessions include those recorded on earlier enrollments of the same hardware, with the same serial number, so a re-enrolled device keeps its history. An unknown asset returns 404 with code asset_not_found; an unknown deviceUserId or externalUserId matches no session and returns an empty list.

Report a login

Send one device field and one user field. Sending both or neither of a pair returns 400.

FieldMax lengthDescription
serialNumber255The device's serial number. Either this or assetId.
assetId255The asset's id. Either this or serialNumber.
externalUserId100Your own id for the user. Its first login creates a device user with auth EXTERNAL; later logins reuse it. Surrounding spaces are removed, and control characters are refused. Either this or deviceUserId.
deviceUserId36The id of an existing Nomid device user. Either this or externalUserId.
userName50Optional display name, used only with externalUserId. A new EXTERNAL user takes it, or its externalUserId cut to 50 characters when it is absent. A later login with a different userName renames the user.

Keep the loginId from the response: it is the receipt that logs out exactly this session. If a login response is lost and you send the login again, a second session is recorded; a logout by device and user closes both.

Report a logout

Send either loginId, or a device field and a user field to close every open session the API opened for that user on that device, including on earlier enrollments of the same hardware.

FieldMax lengthDescription
loginId36The receipt the login returned. A device or user field sent with it must be the session's own, or the request returns 409.
serialNumber255The device's serial number. Not together with assetId.
assetId255The asset's id. Not together with serialNumber.
externalUserId100Your own id for the user. Not together with deviceUserId.
deviceUserId36The Nomid id of the device user. Not together with externalUserId.

The response is 200 with the list of sessions concerned. Logging out a session that is already closed changes nothing and returns it as it is, so a logout can be retried safely. A logout by device and user returns an empty list when the user has no open API session there.

Session fields

Every endpoint returns sessions with these fields. A field without a value is omitted; open is always present. Times are ISO-8601 instants in UTC.

FieldDescription
loginIdThe session's id, the receipt that logs it out.
deviceUserWho logged in: id (the Nomid id), name, auth (PIN, SSO or EXTERNAL) and, for an EXTERNAL user, externalUserId.
assetWhere: assetId, serialNumber and name. Omitted only when the device no longer belongs to any asset.
loginAtWhen the user logged in. Omitted only for a logout the device reported without a login.
logoutAtWhen the session ended. Omitted while it is open.
expiresAtWhen the session expires on its own, if the policy sets an expiry. Sessions reported through the API have none.
opentrue while nobody logged the session out and it has not expired.
loginSourceWho reported the login: DEVICE (the Nomid agent on the device, a PIN or SSO login) or API (your system, through this API).
logoutSourceWho reported the logout: DEVICE, API, or EXPIRY when the session expired. Omitted while the session is open.

Examples

Report a login by serial number for a user of your own system.

curl -X POST "https://api.nomid.tech/emm/api/v1/device-user-logins" \
  -H "X-API-Key: $NOMID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"serialNumber": "R58N123ABCD", "externalUserId": "emp-1042", "userName": "Ana Souza"}'
HTTP/1.1 201 Created

{
  "loginId": "5f0c2a8e-3b1d-4e7a-9c64-2d8f1b7e0a93",
  "deviceUser": {
    "id": "b2e47c19-8a3f-4d65-a0e1-6c9d2f5b8e74",
    "name": "Ana Souza",
    "auth": "EXTERNAL",
    "externalUserId": "emp-1042"
  },
  "asset": {
    "assetId": "k3x9m2pa",
    "serialNumber": "R58N123ABCD",
    "name": "Warehouse scanner 12"
  },
  "loginAt": "2026-10-29T11:02:41.518204Z",
  "open": true,
  "loginSource": "API"
}

Log that session out with its loginId.

curl -X POST "https://api.nomid.tech/emm/api/v1/device-user-logins/logout" \
  -H "X-API-Key: $NOMID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"loginId": "5f0c2a8e-3b1d-4e7a-9c64-2d8f1b7e0a93"}'
HTTP/1.1 200 OK

[
  {
    "loginId": "5f0c2a8e-3b1d-4e7a-9c64-2d8f1b7e0a93",
    "deviceUser": {
      "id": "b2e47c19-8a3f-4d65-a0e1-6c9d2f5b8e74",
      "name": "Ana Souza",
      "auth": "EXTERNAL",
      "externalUserId": "emp-1042"
    },
    "asset": {
      "assetId": "k3x9m2pa",
      "serialNumber": "R58N123ABCD",
      "name": "Warehouse scanner 12"
    },
    "loginAt": "2026-10-29T11:02:41.518204Z",
    "logoutAt": "2026-10-29T19:30:05.204117Z",
    "open": false,
    "loginSource": "API",
    "logoutSource": "API"
  }
]

Or close every open API session of the user on that device.

curl -X POST "https://api.nomid.tech/emm/api/v1/device-user-logins/logout" \
  -H "X-API-Key: $NOMID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"serialNumber": "R58N123ABCD", "externalUserId": "emp-1042"}'

Read the sessions of one device since October 1. This one is a PIN login on the device that expired.

curl "https://api.nomid.tech/emm/api/v1/device-user-logins?serialNumber=R58N123ABCD&from=2026-10-01T00:00:00Z&limit=20" \
  -H "X-API-Key: $NOMID_API_KEY"
HTTP/1.1 200 OK

[
  {
    "loginId": "e91d4b7a-0c2f-4a58-8b13-7f6e5d4c3b2a",
    "deviceUser": {
      "id": "4c8a1e2f-6b3d-4f70-9e15-0a2b3c4d5e6f",
      "name": "Shift 2 operator",
      "auth": "PIN"
    },
    "asset": {
      "assetId": "k3x9m2pa",
      "serialNumber": "R58N123ABCD",
      "name": "Warehouse scanner 12"
    },
    "loginAt": "2026-10-28T14:00:09.731552Z",
    "logoutAt": "2026-10-28T22:00:09.731552Z",
    "expiresAt": "2026-10-28T22:00:09.731552Z",
    "open": false,
    "loginSource": "DEVICE",
    "logoutSource": "EXPIRY"
  }
]

Error: a session the device reported

HTTP/1.1 409 Conflict
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Conflict",
  "status": 409,
  "detail": "The login was reported by the device, not through the API",
  "instance": "/emm/api/v1/device-user-logins/logout",
  "code": "login_not_reported_by_api"
}

Errors

The device-user session endpoints answer 400, 404 and 409 with application/problem+json and a code member to branch on; they send no retryable member. Two exceptions have no code: 401 and 403, and a 400 for an invalid query parameter of GET /device-user-logins.

StatusCodeMeaning
400invalid_argumentLogin or logout: the body is missing or is not valid JSON of the documented shape, both or neither of a device or user pair was sent, a logout without loginId lacks the device or the user, or externalUserId (over 100 characters) or userName (over 50 characters) is too long or has control characters. The detail says which.
400-List only: assetId and serialNumber together, from not earlier than to, from or to not an ISO-8601 instant or outside 1970 to 9999, a limit below 1, or open not true or false.
401-The API key is missing, invalid, expired or revoked.
403-The key lacks DEVICES_READ (list) or DEVICES_COMMAND (login and logout).
404asset_not_foundNo asset with this assetId or serialNumber in the key's company.
404device_user_not_foundNo device user with this deviceUserId in the key's company or, on a logout, none with this externalUserId because it never logged in through the API.
404login_not_foundNo session with this loginId in the key's company.
409no_managed_deviceThe asset has no managed device, so no login can be recorded on it.
409device_user_disabledThe device user is disabled.
409device_user_not_externalThe device user with this externalUserId no longer has auth EXTERNAL.
409login_device_mismatchThe session with this loginId did not happen on the device sent with it.
409login_user_mismatchThe session with this loginId is not the sent user's.
409login_not_reported_by_apiThe session was reported by the device, a PIN or SSO login on the Nomid agent. The device closes it, not the API.

Rate limits

These endpoints are not part of the write limit of 10 requests per minute per key that device commands, policy changes and provisioning QR codes share. Build your client to back off on 429 anyway.

MCP tool

The read-only MCP tool list_device_user_logins takes the same filters as arguments and needs DEVICES_READ. With Sign in with Nomid, a user who sees only some policies gets only the sessions on assets of those policies. Reporting logins and logouts is REST only: no MCP tool does it.

list_device_user_loginsDEVICES_READDevice-user sessions, newest first, with the filters of GET /device-user-logins: who logged in on which asset, when, and who reported the login and the logout. Follows the caller's policy scope. Tool error if the asset is not found.

MCP server

Choose Your Time

Loading...
Open booking calendar