This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

REST API

Use the 2log REST API to manage users, groups, permissions and logs programmatically.

The 2log REST API allows you to manage your instance programmatically. This is useful for automating recurring tasks, integrating 2log with other systems, or building your own tools on top of it.

All examples in this section use curl and assume your 2log server is reachable at http://your-server. The Caddy reverse proxy forwards everything under /api to the QuickHub REST backend, so all API endpoints are prefixed with /api.

How the REST API works

Under the hood, 2log is built on the QuickHub framework. QuickHub provides real-time data synchronization over WebSockets. Resources (such as the user list or a device configuration) live on the server and are identified by a resource path like labcontrol/users.

The REST API gives you plain HTTP access to these same resources. Since slashes in URLs would be interpreted as path separators, the REST API uses dots as namespace separators in the URL. The server translates dots back to slashes internally:

URL path component Internal resource path
labcontrol.users labcontrol/users
labcontrol.groups labcontrol/groups
labcontrol.users.groups.{uuid} labcontrol/users/groups/{uuid}

Resource types

The REST API exposes three types of endpoints, each mapping to a different QuickHub resource type:

Endpoint prefix Resource type Description
/api/lists/{resource} Synchronized List Ordered collections of items (e.g. users, groups, permissions). Supports GET, POST, PUT, PATCH, DELETE.
/api/objects/{resource} Object Key-value stores (e.g. the current user’s profile). Supports GET, PUT, PATCH.
/api/services/{service}/{method} Service RPC-style function calls (e.g. addUser, getLogs). Always uses POST.

Additionally, there are endpoints for binary data:

Endpoint prefix Description
/api/images/{resource} Upload, list and download images.
/api/files Generic file upload and download.

The following pages explain each area in detail.

1 - Authentication

How to log in, manage session tokens, and log out via the REST API.

Before you can use the API, you need to log in with your admin account. The login endpoint returns a session token that you include in all subsequent requests.

Log in

curl -s -X POST http://your-server/api/login \
  -H "Content-Type: application/json" \
  -d '{"user": "admin@fablab.org", "pass": "your-password"}'

The server responds with a token:

{"token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}

For convenience, you can store the token in a shell variable:

TOKEN=$(curl -s -X POST http://your-server/api/login \
  -H "Content-Type: application/json" \
  -d '{"user": "admin@fablab.org", "pass": "your-password"}' | jq -r '.token')

Providing the token

Include the token in every request. The server accepts it in three places (checked in this order):

  1. Authorization header (recommended):
    Authorization: Bearer $TOKEN
    
  2. Session cookie (set automatically after login if you preserve cookies)
  3. Query parameter (fallback):
    ?token=$TOKEN
    

Already logged in

If the session cookie already contains a valid token, a second login request returns the existing token without creating a new session.

Log out

When you are done, invalidate the session:

curl -X POST http://your-server/api/logout \
  -H "Authorization: Bearer $TOKEN"

Response:

{"success": true}

Error responses

Situation Status Message
Missing user or pass 400 Missing credentials
Unknown user 401 User not found
Wrong password 401 Incorrect password
Account not allowed 403 Permission denied
Expired or invalid token (on other endpoints) 403 Invalid token. Please log in and try again.

API tokens

For automated or long-running integrations you can create API tokens instead of using session-based login. API tokens are managed through the admin UI and can be used directly as bearer tokens — no login step required.

Creating an API token

  1. Open the Admin panel in the 2log UI.
  2. Navigate to the API Tokens section.
  3. Provide a name, an optional description, permissions, and an optional expiration date.
  4. Click Create. The token string is shown once — copy and store it securely.

Using an API token

Use the token exactly like a session token. The server accepts it in the same three places:

# Authorization header (recommended)
curl http://your-server/api/some-endpoint \
  -H "Authorization: Bearer <API_TOKEN>"

# Query parameter
curl "http://your-server/api/some-endpoint?token=<API_TOKEN>"

Key differences from session tokens

Session token API token
Created via POST /api/login Admin UI
Lifetime Expires on session timeout Valid until expiration date (or indefinitely if none is set)
Scope Full admin access Configurable permissions
Revocation POST /api/logout Delete in Admin UI

2 - Managing Users

Create, read, update and delete users via the REST API.

User list (admin)

Users are stored as a synchronized list resource at labcontrol.users. You need LAB_ADMIN, IS_ADMIN, or LAB_SEE_USERS permissions to access this resource.

List all users

curl http://your-server/api/lists/labcontrol.users \
  -H "Authorization: Bearer $TOKEN"

The response is a JSON array. Each item contains a data object with the user fields and a uuid at the top level:

[
  {
    "data": {
      "name": "Max",
      "surname": "Mustermann",
      "mail": "max@fablab.org",
      "alias": "maxm",
      "role": "mem",
      "course": "",
      "balance": 1500,
      "creditLimit": -1,
      "state": 1,
      "lastLogin": "2024-01-15T10:30:00.000",
      "creation": "2023-06-01T08:00:00.000",
      "uuid": "f47ac10b58cc4372a5670e02b2c3d479"
    },
    "uuid": "f47ac10b58cc4372a5670e02b2c3d479"
  }
]

Field reference:

Field Type Description
name string First name
surname string Last name
mail string Email address
alias string Display name (chosen by user)
role string mem (member), empl (employee), ext (external/guest)
course string Course or semester (e.g. WS2024)
balance int Account balance in cents
creditLimit int Maximum negative balance in cents. -1 = use global default
state int 0 = idle, 1 = active, 2 = disabled, 3 = deleted
lastLogin string ISO 8601 timestamp of last login
creation string ISO 8601 timestamp of account creation
uuid string Unique user ID

Get a single user

By UUID:

curl http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

By index (0-based position in the list):

curl http://your-server/api/lists/labcontrol.users/0 \
  -H "Authorization: Bearer $TOKEN"

Update user properties

To change individual properties of an existing user, use PATCH. Only the fields you specify are changed:

curl -X PATCH http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "role": "empl"
    }
  }'

Replace a user record

If you want to replace the entire user object, use PUT:

curl -X PUT http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "name": "Max",
      "surname": "Mustermann",
      "mail": "max@fablab.org",
      "role": "empl",
      "balance": 3000
    }
  }'

Remove a user

curl -X DELETE http://your-server/api/lists/labcontrol.users/f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

Add a user via the lab service

To create a new user with permissions, cards, and group assignments in one step, use the lab service. This is the recommended way to add users because it handles all related data at once. You need LAB_ADMIN or LAB_MODIFY_USERS permissions.

curl -X POST http://your-server/api/services/lab/addUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user": {
      "name": "Lisa",
      "surname": "Lasercut",
      "mail": "lisa@fablab.org",
      "role": "mem"
    },
    "permissions": {},
    "card": {},
    "groups": {}
  }'

To create a user or update them if they already exist (useful for CSV imports), use addOrUpdateUser:

curl -X POST http://your-server/api/services/lab/addOrUpdateUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "user": {
      "name": "Lisa",
      "surname": "Lasercut",
      "mail": "lisa@fablab.org",
      "role": "mem"
    },
    "permissions": {},
    "card": {},
    "groups": {}
  }'

Delete a user via the lab service

curl -X POST http://your-server/api/services/lab/deleteUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userID": "f47ac10b58cc4372a5670e02b2c3d479"}'

Transfer money

To add or deduct credit from a user’s balance, use the transferMoney method. The value is in cents (positive = credit, negative = debit). Requires LAB_ADMIN or LAB_SERVICE permissions.

curl -X POST http://your-server/api/services/lab/transferMoney \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "value": 500,
    "description": "Workshop fee refund"
  }'
Parameter Type Required Description
userID string yes UUID of the user
value int yes Amount in cents
description string no Reason for the transfer

Reset a user’s password

Sends a temporary password to the user by email:

curl -X POST http://your-server/api/services/lab/resetPassword \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"userID": "f47ac10b58cc4372a5670e02b2c3d479"}'

Look up a user by card ID

Requires LAB_ADMIN, LAB_SERVICE, or LAB_SEE_USERS permissions.

curl -X POST http://your-server/api/services/lab/getUserForCard \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cardID": "04:A3:2B:1C:D4:E5:F6"}'

Look up a user by external reference

If users are linked to an external system via extRef, you can look them up:

curl -X POST http://your-server/api/services/lab/getUserForExternalReference \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"extRef": "EXT-12345"}'

Response:

{
  "errorCode": 0,
  "userID": "f47ac10b58cc4372a5670e02b2c3d479",
  "userName": "Max",
  "eMail": "max@fablab.org",
  "balance": 1500
}

If no user is found, errorCode is -1.

Reading your own user data

To read the data of the currently logged-in user as an object resource, use labcontrol.user (singular). This does not require admin permissions.

curl http://your-server/api/objects/labcontrol.user \
  -H "Authorization: Bearer $TOKEN"

The response wraps each property in a data field:

{
  "name": {"data": "Max"},
  "surname": {"data": "Mustermann"},
  "mail": {"data": "max@fablab.org"},
  "alias": {"data": "maxm"},
  "role": {"data": "mem"},
  "balance": {"data": 1500},
  "state": {"data": 1},
  "creditLimit": {"data": -1},
  "course": {"data": ""},
  "lastLogin": {"data": "2024-01-15T10:30:00.000"},
  "creation": {"data": "2023-06-01T08:00:00.000"},
  "uuid": {"data": "f47ac10b58cc4372a5670e02b2c3d479"}
}

Read a single property

curl http://your-server/api/objects/labcontrol.user/balance \
  -H "Authorization: Bearer $TOKEN"

Update your own profile

Regular users can only modify their alias:

curl -X PUT http://your-server/api/objects/labcontrol.user/alias \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": "my-new-alias"}'

Admins (LAB_ADMIN, IS_ADMIN, or LAB_MODIFY_USERS) can additionally modify name, surname, mail, role, course, creditLimit, and extRef.

3 - Resources (Machines)

Read and manage resource controllers, their aspects (billing, QR code, permissions, etc.) via the REST API.

Resources represent the logical machines and devices managed by 2log (e.g. a laser cutter, a 3D printer, or a suction system). Each resource is a bundle that combines a controller, a resource state, and a set of aspects that add capabilities like billing, logging, or QR code authentication.

Permissions

  • Admins (IS_ADMIN): full read/write access to all resource objects and properties.
  • All authenticated users: read-only access to a subset of public properties (see below).

Resource list

All resources are stored as a synchronized list at 2log.resources. This list is readable by any authenticated user, but only admins can add or remove entries.

List all resources

curl http://your-server/api/lists/2log.resources \
  -H "Authorization: Bearer $TOKEN"

The response is a JSON array. Each item contains a data object with the resource properties and a uuid:

[
  {
    "data": {
      "displayName": "Laser Cutter",
      "resourceUid": "laser-cutter-01",
      "systemType": "machines",
      "controllerType": "genericPrimaryBundle",
      "controllerState": 0,
      "resourceState": 0,
      "userName": "",
      "userType": "",
      "bundleType": "genericPrimaryBundle"
    },
    "uuid": "laser-cutter-01"
  }
]

Public properties (visible to all authenticated users):

Field Type Description
displayName string Human-readable name of the resource
controllerState int Current state of the controller
systemType string Resource category (e.g. machines, suctions)
userType string User-facing machine type label (free-form, e.g. Lasercutter, 3D-Drucker). Unlike systemType, this is a display label that can be chosen freely.
resourceUid string Unique resource identifier

Admin-only properties (additionally visible to admins):

Field Type Description
controllerType string Bundle type (e.g. genericPrimaryBundle, prusa3DPrinterBundle)
resourceState int Current resource state
userName string Name of the currently logged-in user
bundleType string Bundle type identifier

Get a single resource

curl http://your-server/api/lists/2log.resources/laser-cutter-01 \
  -H "Authorization: Bearer $TOKEN"

Resource objects (admin only)

Each resource bundle and its sub-components are also available as individual object resources. These endpoints require IS_ADMIN permission.

Resource bundle

Returns all properties of a resource bundle as an object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01 \
  -H "Authorization: Bearer $TOKEN"

The response wraps each property in a data field (standard QuickHub object format):

{
  "displayName": {"data": "Laser Cutter"},
  "resourceUid": {"data": "laser-cutter-01"},
  "systemType": {"data": "machines"},
  "controllerType": {"data": "genericPrimaryBundle"},
  "controllerState": {"data": 0},
  "resourceState": {"data": 0},
  "userName": {"data": ""},
  "userType": {"data": ""},
  "imageScale": {"data": 1.0},
  "imageCenterX": {"data": 0},
  "imageCenterY": {"data": 0}
}

Resource sub-object

Returns the resource state object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.resource \
  -H "Authorization: Bearer $TOKEN"

Controller sub-object

Returns the controller state object:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.controller \
  -H "Authorization: Bearer $TOKEN"

Aspects

Aspects are modular capabilities attached to a resource. Each aspect is accessible as an object resource at 2log.resources.{resourceUid}.{aspectName}. All aspect endpoints require IS_ADMIN permission.

The available aspects depend on the bundle type:

Aspect name genericPrimaryBundle prusa3DPrinterBundle genericSecondaryBundle Description
billing yes yes Usage-based billing
dblogs yes yes Database logging
permissioncheck yes yes Permission validation
dot yes yes 2log Dot hardware enabler
qrcode yes yes QR code authentication
secondary yes Companion/secondary resource control

billing – Usage-based billing

The billing aspect controls how usage of a resource is charged.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.billing \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
payingMode int Billing mode (see table below)
pricePerUnit int Price per unit in cents
unitDuration int Duration of one billing unit (in seconds)
employeesForFree bool If true, employees (empl role) are not charged
minimumCreditBalance int Minimum credit balance required to start a session (in cents)

Billing modes (payingMode):

Value Mode Description
0 DISABLED No billing
1 BILLING_BY_SESSION_TIME Charged based on total session time
2 BILLING_BY_PRODUCTIVE_TIME Charged based on productive (active) time only
3 BILLING_PER_JOB Flat fee per job
4 BILLING_WHEN_ENABLED Charged upon activation

To update billing settings:

curl -X PUT http://your-server/api/objects/2log.resources.laser-cutter-01.billing/payingMode \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": 1}'

qrcode – QR code authentication

The QR code aspect manages how users authenticate at a machine using QR codes (scanned via the 2log mobile app).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
mode int QR code mode (see table below)
code string Current QR code value

QR code modes (mode):

Value Mode Description
0 DISABLED QR code authentication is off
1 STATIC A fixed QR code is used (defaults to the resource UID)
2 DYNAMIC The server generates a new random code (12 characters) periodically

Reading the current QR code

To read the current QR code value for a machine:

curl http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode/code \
  -H "Authorization: Bearer $TOKEN"
{"data": "A3xK9mP2qR7w"}

In static mode the code value stays the same (typically the resourceUid). In dynamic mode the server generates a new 12-character code automatically. To get the current code, simply read this property – the server always returns the currently valid value.

Changing the QR code mode

curl -X PUT http://your-server/api/objects/2log.resources.laser-cutter-01.qrcode/mode \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": 2}'

dblogs – Database logging

The logging aspect tracks resource usage and writes log entries to the database.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.dblogs \
  -H "Authorization: Bearer $TOKEN"
Property Type Description
dbref string Database reference identifier for this resource’s logs

This aspect works together with the billing aspect: when a session ends, the billing information is automatically written as a log entry. The resulting logs can be queried via the getLogs service method.

permissioncheck – Permission validation

The permission check aspect verifies whether a user has the required permissions to use a resource. It works asynchronously – when a user attempts to authenticate, it queries the configured permission service and returns the result.

curl http://your-server/api/objects/2log.resources.laser-cutter-01.permissioncheck \
  -H "Authorization: Bearer $TOKEN"

secondary – Companion resource control

The companion controller aspect links a primary resource to a secondary resource (e.g. linking a suction system to a laser cutter so that the suction starts automatically).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.secondary \
  -H "Authorization: Bearer $TOKEN"

Properties:

Property Type Description
resourceUid string UID of the linked secondary resource
interceptWhenNotRunning bool Block the primary resource if the secondary is not running
desiredResourceState int Target state for the secondary resource
forceInterception bool Force interception regardless of state
ready bool Whether the secondary resource is ready

dot – 2log Dot hardware enabler

The Dot aspect integrates with the physical 2log Dot device (an NFC/RFID reader attached to the machine).

curl http://your-server/api/objects/2log.resources.laser-cutter-01.dot \
  -H "Authorization: Bearer $TOKEN"
Property Type Description
dotDeviceMapping string Mapping identifier for the associated Dot hardware device

Aspect lists

You can retrieve a flat list of all aspects of a given type across all resources. This is useful for getting an overview (e.g. all billing configurations or all QR codes at once).

The endpoint is a synchronized list at 2log.resources.{aspectType}:

# Get all billing aspects across all resources
curl http://your-server/api/lists/2log.resources.billing \
  -H "Authorization: Bearer $TOKEN"

# Get all QR code aspects across all resources
curl http://your-server/api/lists/2log.resources.qrcode \
  -H "Authorization: Bearer $TOKEN"

The valid aspect type values are: billing, dblogs, permissioncheck, secondary, dot, qrcode.


Creating and deleting resources

Resources are managed via the resources service. See the Service Reference for details.

Create a resource

curl -X POST http://your-server/api/services/resources/newController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Laser Cutter",
    "type": "machines",
    "uid": "laser-cutter-01"
  }'

Delete a resource

curl -X POST http://your-server/api/services/resources/deleteController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uid": "laser-cutter-01"}'

4 - Groups and Permissions

Manage groups, individual permissions and RFID cards via the REST API.

Managing groups

Groups are stored as a synchronized list resource at labcontrol.groups. You need LAB_ADMIN, IS_ADMIN, or LAB_SEE_GROUPS permissions to read groups and LAB_MODIFY_GROUPS to modify them.

List all groups

curl http://your-server/api/lists/labcontrol.groups \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "name": "Woodworking",
      "description": "Access to all woodworking machines",
      "systemGroup": false,
      "entities": [],
      "uuid": "a1b2c3d4e5f67890abcdef1234567890"
    },
    "uuid": "a1b2c3d4e5f67890abcdef1234567890"
  }
]

The system automatically creates three system groups for the built-in roles mem, empl, and ext. Groups with systemGroup: true should not be modified manually.

Create a new group

curl -X POST http://your-server/api/services/lab/addGroup \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Electronics Lab",
    "description": "Access to soldering stations and measurement equipment"
  }'

Requires LAB_ADMIN, LAB_SERVICE, or LAB_MODIFY_GROUPS.

Update group properties

curl -X PATCH http://your-server/api/lists/labcontrol.groups/a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "description": "Access to all woodworking and CNC machines"
    }
  }'

Delete a group

curl -X DELETE http://your-server/api/lists/labcontrol.groups/a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN"

Group entities (machines in a group)

Each group has a nested list of entities (the machines and resources it grants access to). This list is accessible at labcontrol.groups.entities.{groupUUID}:

curl http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "resourceID": "laser-cutter-01",
      "type": 0,
      "active": true,
      "expires": false,
      "expirationDate": "",
      "creationDate": "2024-01-10T14:00:00.000"
    },
    "uuid": "..."
  }
]

Add a machine to a group

curl -X POST http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "resourceID": "reflow-oven-01",
      "active": true,
      "expires": false
    }
  }'

Remove a machine from a group

curl -X DELETE http://your-server/api/lists/labcontrol.groups.entities.a1b2c3d4e5f67890abcdef1234567890/ENTITY_UUID \
  -H "Authorization: Bearer $TOKEN"

User group assignments

Group assignments for a user are stored as a nested list at labcontrol.users.groups.{userUUID}. Each entry represents a group membership with optional expiration.

List group assignments

curl http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "groupID": "a1b2c3d4e5f67890abcdef1234567890",
      "active": true,
      "expires": false,
      "expirationDate": "",
      "creationDate": "2024-01-10T14:00:00.000",
      "type": 0
    },
    "uuid": "..."
  }
]

Assign a group to a user

curl -X POST http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "groupID": "b2c3d4e5f67890abcdef1234567890a1",
      "active": true,
      "expires": false
    }
  }'

Assign with expiration date

curl -X POST http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "groupID": "b2c3d4e5f67890abcdef1234567890a1",
      "active": true,
      "expires": true,
      "expirationDate": "2025-03-31T23:59:59.000"
    }
  }'

Deactivate a group assignment

curl -X PATCH http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479/MEMBERSHIP_UUID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "active": false
    }
  }'

Remove a group assignment

curl -X DELETE http://your-server/api/lists/labcontrol.users.groups.f47ac10b58cc4372a5670e02b2c3d479/MEMBERSHIP_UUID \
  -H "Authorization: Bearer $TOKEN"

Individual permissions

Permissions for a specific user are stored at labcontrol.users.permissions.{userUUID}. Each entry grants access to a specific resource (machine).

List user permissions

curl http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"
[
  {
    "data": {
      "resourceID": "laser-cutter-01",
      "type": 0,
      "active": true,
      "expires": true,
      "expirationDate": "2025-06-30T23:59:59.000",
      "creationDate": "2024-01-10T14:00:00.000"
    },
    "uuid": "..."
  }
]

Grant a permission

curl -X POST http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "resourceID": "cnc-mill-02",
      "active": true,
      "expires": false
    }
  }'

Revoke a permission

curl -X DELETE http://your-server/api/lists/labcontrol.users.permissions.f47ac10b58cc4372a5670e02b2c3d479/PERMISSION_UUID \
  -H "Authorization: Bearer $TOKEN"

User cards

RFID cards assigned to a user are stored at labcontrol.users.cards.{userUUID}:

curl http://your-server/api/lists/labcontrol.users.cards.f47ac10b58cc4372a5670e02b2c3d479 \
  -H "Authorization: Bearer $TOKEN"

Check if a user has permission

The hasPermission method checks if a user or card has access to a specific resource. It evaluates system groups, custom groups, and individual permissions in one call. Requires LAB_SERVICE permissions.

By user ID:

curl -X POST http://your-server/api/services/lab/hasPermission \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "resourceID": "laser-cutter-01"
  }'

By card ID:

curl -X POST http://your-server/api/services/lab/hasPermission \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "resourceID": "laser-cutter-01"
  }'

5 - Working with Logs

Query and create log entries via the REST API.

2log records all machine usage, transactions, and system events as log entries. You can query and filter these logs via the lab service.

Permissions

  • Admins (LAB_ADMIN, LAB_SERVICE, or LAB_SEE_LOGS): can query all logs.
  • Regular users: can only see their own logs. The server automatically adds a userID filter matching the logged-in user.

Querying logs

Use the getLogs service method with a filter object:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {},
      "sort": {"timestamp": -1},
      "limit": 50
    }
  }'

The filter object

Field Type Description
match object MongoDB-style match criteria (see below)
sort object Sort order, e.g. {"timestamp": -1} for newest first, {"timestamp": 1} for oldest first
from string ISO 8601 datetime – start of time range
to string ISO 8601 datetime – end of time range (defaults to now if omitted)
limit int Maximum number of results (-1 or omit for unlimited)

Match criteria

The match object filters log entries by exact field values:

Field Type Description
userID string Filter by user UUID
resourceID string Filter by machine / resource ID
logType int Filter by event type (see table below)

Log event types

Value Name Description
0 BILL Completed session with billing
1 SWITCH_ON Something was switched on
2 SWITCH_OFF Something was switched off
3 START A machine was started
4 STOP A machine was stopped
5 EVENT General event
6 LOGIN User logged in
7 LOGOUT User logged out
8 WARNING Warning
9 ERROR Error
10 OPEN Something was opened (cabinet, lid)
11 CLOSED Something was closed
12 TRANSFER Balance transfer (top-up or deduction)
13 JOB Job with duration
14 OFFLINE Device went offline

Log entry format

Each log entry in the response contains these fields:

{
  "logID": "60a7b2c3d4e5f67890abcdef",
  "resourceID": "laser-cutter-01",
  "userID": "f47ac10b58cc4372a5670e02b2c3d479",
  "userName": "Max Mustermann",
  "email": "max@fablab.org",
  "cardID": "04:A3:2B:1C:D4:E5:F6",
  "logType": 0,
  "units": 120,
  "price": 600,
  "description": "Laser cutting session",
  "timestamp": "2024-01-15T14:30:00.000",
  "startTime": "2024-01-15T14:00:00.000",
  "endTime": "2024-01-15T14:30:00.000",
  "executive": "admin-user-uuid",
  "sessionID": "session-uuid",
  "extType": "",
  "extRef": ""
}
Field Type Description
logID string Unique log entry ID
resourceID string Machine or resource that generated this log
userID string UUID of the user involved
userName string Name of the user at the time of the event
email string Current email of the user (joined from user data)
cardID string RFID card used (if applicable)
logType int Event type (see table above)
units int Usage units (interpretation depends on machine)
price int Cost in cents
description string Human-readable description
timestamp string When the log was created
startTime string Start of the session/event
endTime string End of the session/event
executive string UUID of the user/service that triggered the event
sessionID string Session identifier (groups related log entries)
extType string External system type (e.g. 2log-paydesk)
extRef string External reference ID

Examples

Logs for a specific user

Get the 20 most recent logs for a user:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "userID": "f47ac10b58cc4372a5670e02b2c3d479"
      },
      "sort": {"timestamp": -1},
      "limit": 20
    }
  }'

Logs for a specific machine

Get all logs for the laser cutter:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "resourceID": "laser-cutter-01"
      },
      "sort": {"timestamp": -1}
    }
  }'

Logs in a time range

Get all billing events from January 2024:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "logType": 0
      },
      "from": "2024-01-01T00:00:00.000",
      "to": "2024-02-01T00:00:00.000",
      "sort": {"timestamp": -1}
    }
  }'

Combining filters

Get all laser cutter sessions for a specific user in Q1 2024:

curl -X POST http://your-server/api/services/lab/getLogs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "match": {
        "userID": "f47ac10b58cc4372a5670e02b2c3d479",
        "resourceID": "laser-cutter-01"
      },
      "from": "2024-01-01T00:00:00.000",
      "to": "2024-04-01T00:00:00.000",
      "sort": {"timestamp": -1}
    }
  }'

Adding a log entry

To create a log entry programmatically, use the addLog method. Requires LAB_ADMIN or LAB_SERVICE permissions.

curl -X POST http://your-server/api/services/lab/addLog \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceID": "laser-cutter-01",
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "logType": 5,
    "description": "Manual maintenance note",
    "units": 0,
    "price": 0
  }'

The fields in the request body correspond to the log entry fields described above. The timestamp is set automatically to the current time.

6 - Service Reference

Complete reference for all available service methods.

Services provide RPC-style function calls. All service calls use POST:

POST /api/services/{serviceName}/{methodName}

The request body is a JSON object with the method parameters. The server waits up to 30 seconds for a response before returning a 504 timeout.

Discovering services

List all registered services and their methods:

curl http://your-server/api/services \
  -H "Authorization: Bearer $TOKEN"

Get info about a specific service:

curl http://your-server/api/services/lab \
  -H "Authorization: Bearer $TOKEN"
{
  "name": "lab",
  "methods": ["addLog", "getLogs", "resetPassword", "addUser", "deleteUser", ...]
}

lab service

The main service for user management, access control and logging.

Method Description Permissions
addUser Create a new user LAB_ADMIN, LAB_MODIFY_USERS
addOrUpdateUser Create or update a user LAB_ADMIN, LAB_MODIFY_USERS
deleteUser Delete a user LAB_ADMIN, LAB_MODIFY_USERS
resetPassword Send a temporary password by email (any valid token)
transferMoney Add/deduct credit LAB_ADMIN, LAB_SERVICE
getUserForCard Look up user by RFID card LAB_ADMIN, LAB_SERVICE, LAB_SEE_USERS
getUserForExternalReference Look up user by external ID LAB_ADMIN, LAB_SERVICE, LAB_SEE_USERS
hasPermission Check access to a resource LAB_SERVICE
getLogs Query log entries LAB_ADMIN, LAB_SERVICE, LAB_SEE_LOGS (or own logs)
addLog Create a log entry LAB_ADMIN, LAB_SERVICE
addGroup Create a new group LAB_ADMIN, LAB_SERVICE, LAB_MODIFY_GROUPS
getAccumulatedCostsForUser Get total costs for a user in a date range LAB_ADMIN, LAB_SERVICE, LAB_SEE_LOGS (or own costs)
addSystemUser Create a system/admin user LAB_ADMIN, IS_ADMIN, LAB_SERVICE
changeUserLevel Change a system user’s role LAB_ADMIN, IS_ADMIN, LAB_SERVICE

See Users, Groups & Permissions, and Logs for detailed examples.

getAccumulatedCostsForUser

Returns the total accumulated costs for a user within a given date range. The server aggregates all log entries matching the user and time range, and returns the summed totalCost.

Unprivileged users (without LAB_ADMIN, LAB_SERVICE, or LAB_SEE_LOGS permission) can only query their own costs — the userID parameter is ignored and automatically set to the authenticated user’s ID.

curl -X POST http://your-server/api/services/lab/getAccumulatedCostsForUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "from": "2024-01-01T00:00:00.000",
    "to": "2024-02-01T00:00:00.000"
  }'
Parameter Type Required Description
userID string yes UUID of the user to query costs for
from datetime yes Start of the date range (ISO 8601)
to datetime no End of the date range (ISO 8601). Defaults to current time if omitted

Response:

[
  {
    "totalCost": 4250
  }
]
Field Type Description
totalCost int Sum of all price values (in cents) from matching log entries

addSystemUser

Creates or updates a system-level user (for admin panel access).

curl -X POST http://your-server/api/services/lab/addSystemUser \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "name": "Admin User",
    "eMail": "admin@fablab.org",
    "level": "admin"
  }'
Parameter Type Required Description
userID string yes UUID of the lab user to promote
name string yes Display name
eMail string yes Email address
level string yes Role level (e.g. admin, viewer)

changeUserLevel

Changes the system role of an existing system user.

curl -X POST http://your-server/api/services/lab/changeUserLevel \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "level": "viewer"
  }'

payment service

Handles point-of-sale billing operations (used by the 2log PayDesk).

Method Description Permissions
preparebill Validate a shopping cart and calculate totals (any valid token)
bill Execute a bill (deduct balance, create logs) IS_ADMIN, LAB_ADMIN, LAB_SEND_BILLS
getsales Get product sales history for a date range (any valid token)

preparebill

Validates a shopping cart, resolves the user, and calculates totals per accounting code. Does not deduct money.

curl -X POST http://your-server/api/services/payment/preparebill \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "bill": [
      {"name": "Laser time 30min", "price": 500, "accountingCode": "laser"},
      {"name": "Material fee", "price": 200, "accountingCode": "material"}
    ],
    "total": 700
  }'
Parameter Type Required Description
cardID string one of cardID/userID RFID card to identify the user
userID string one of cardID/userID User UUID (alternative to cardID)
bill array yes List of items, each with name, price (cents), accountingCode
total int yes Expected total in cents

Response:

{
  "errcode": 0,
  "errstring": "",
  "userID": "f47ac10b...",
  "name": "Max",
  "surname": "Mustermann",
  "eMail": "max@fablab.org",
  "total": 700,
  "discountTotal": 700,
  "bills": [
    {
      "accountingCode": "laser",
      "totalBrutto": 500,
      "totalNetto": 500,
      "discountPercent": 0,
      "items": [...]
    }
  ]
}

bill

Executes the billing: deducts the amount from the user’s balance, creates log entries, and sends a payment confirmation email.

curl -X POST http://your-server/api/services/payment/bill \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardID": "04:A3:2B:1C:D4:E5:F6",
    "userID": "f47ac10b58cc4372a5670e02b2c3d479",
    "bills": [
      {
        "accountingCode": "laser",
        "totalNetto": 500,
        "items": [
          {"uuid": "item-1", "name": "Laser time 30min", "price": 500, "newprice": 500, "flat": false}
        ]
      }
    ],
    "total": 500,
    "discountTotal": 500
  }'
Parameter Type Required Description
cardID string one of cardID/userID RFID card ID
userID string one of cardID/userID User UUID
bills array yes Array of bill groups (from preparebill response)
total int yes Original total in cents
discountTotal int yes Final total after discounts in cents
cartID string no Unique cart ID (prevents double billing)

Error codes:

errcode Description
0 Success
-2 Unknown user
-3 Invalid parameters
-4 Cart already paid (duplicate cartID)
-5 Credit limit exceeded

getsales

Returns product sales history for a given date range.

curl -X POST http://your-server/api/services/payment/getsales \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "2024-01-01T00:00:00.000",
    "to": "2024-02-01T00:00:00.000"
  }'

devices service

Manages IoT device mappings and firmware updates.

Method Description
hookWithShortID Map a device to a resource by its short ID
unhookWithShortID Remove a device mapping by its short ID
getDeviceTypeWithShortID Get the device type for a short ID
getDeviceTypeWithID Get the device type for a UUID
checkForUpdates Check for available firmware updates
startUpdate Start a firmware update

hookWithShortID

Maps a physical device (identified by its short ID printed on the hardware) to a logical resource name.

curl -X POST http://your-server/api/services/devices/hookWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "AB12",
    "mapping": "laser-cutter-01",
    "force": false,
    "expectedType": "switch"
  }'
Parameter Type Required Description
shortID string yes Short ID of the device
mapping string yes Logical resource name to assign
force bool no Overwrite existing mapping (default: false)
expectedType string no Expected device type; fails if mismatch

Error codes in response:

errorcode Description
0 Success
-11 Device not found
-12 Wrong device type

unhookWithShortID

curl -X POST http://your-server/api/services/devices/unhookWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shortID": "AB12"}'

getDeviceTypeWithShortID

curl -X POST http://your-server/api/services/devices/getDeviceTypeWithShortID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shortID": "AB12"}'

Response:

{"deviceType": "switch", "errorcode": 0}

getDeviceTypeWithID

curl -X POST http://your-server/api/services/devices/getDeviceTypeWithID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uuid": "device-uuid-here"}'

checkForUpdates

curl -X POST http://your-server/api/services/devices/checkForUpdates \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mapping": "laser-cutter-01"}'

startUpdate

curl -X POST http://your-server/api/services/devices/startUpdate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mapping": "laser-cutter-01",
    "url": "https://firmware.example.com/update.bin"
  }'

machineControl service

Handles the association between 2log controllers (Switch, Dot) and machines.

Method Description
hookSwitch Assign a 2log Switch to a machine
hookDot Assign a 2log Dot to a machine

hookSwitch

Links a 2log Switch device to a machine controller.

curl -X POST http://your-server/api/services/machineControl/hookSwitch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "AB12",
    "deviceID": "machine-controller-id",
    "force": false
  }'
Parameter Type Required Description
shortID string yes Short ID of the Switch device
deviceID string yes ID of the machine controller to attach to
force bool no Overwrite existing assignment

hookDot

Links a 2log Dot device to a machine controller.

curl -X POST http://your-server/api/services/machineControl/hookDot \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "shortID": "CD34",
    "deviceID": "machine-controller-id",
    "force": false
  }'

resources service

Manages 2log resource controllers (the logical representations of machines).

Method Description
newController Create a new resource controller
deleteController Delete a resource controller

newController

curl -X POST http://your-server/api/services/resources/newController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Laser Cutter",
    "type": "machines",
    "uid": "laser-cutter-01"
  }'
Parameter Type Required Description
name string yes Display name
type string yes Resource type (e.g. machines, suctions)
uid string yes Unique device/resource ID

Response:

{"success": true, "data": {...}}

deleteController

curl -X POST http://your-server/api/services/resources/deleteController \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"uid": "laser-cutter-01"}'

codeAuthenticator service

Handles QR-code based authentication (used by the 2log mobile app).

Method Description
authenticate Authenticate a session via a temporary code

authenticate

The 2log app displays a QR code containing a temporary code. When scanned (e.g. by a terminal), this method is called to authenticate the session.

curl -X POST http://your-server/api/services/codeAuthenticator/authenticate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"code": "https://2log.app/AB3F7K9X"}'
Parameter Type Required Description
code string yes The temporary authentication code

Response:

{"errcode": 0}

errcode -1 means the code is unknown or expired.

7 - Error Handling

HTTP status codes and error response format.

Error response format

All error responses follow a consistent JSON format:

{"error": true, "code": 403, "message": "Invalid token. Please log in and try again."}

HTTP status codes

Code Meaning
200 Success
201 Created (file upload)
400 Invalid request data, missing parameters, or malformed JSON
401 Authentication failed (wrong password, unknown user)
403 Invalid token or insufficient permissions
404 Resource, item, property, service, or method not found
405 HTTP method not supported for this endpoint
500 Internal server error (e.g. resource could not be accessed)
502 Service call returned invalid data
504 Service call timed out (30 second limit)

Common error messages

Message Cause
Missing credentials Login request without user or pass
Invalid token. Please log in and try again. Token expired or invalid
Permission denied Authenticated but lacking the required permission
Missing 'data' field POST/PUT/PATCH without data in body
Missing item identifier PUT/PATCH/DELETE on a list without specifying an ID
Item not found / Property not found ID or property does not exist
Service not found Unknown service name
Unknown method Service exists but method name is wrong
Service call timed out Service did not respond within 30 seconds