API
The central server exposes a RESTful API for managing scales, settings, fetching historical data, current status, and more. The web interface uses the browser to access the API endpoints, any other service can also execute the same requests.
Most API endpoints have the following request prefix: /api/v1/
The full API endpoint description and documentation can be found on any running instance of the server at /scalar, for example http://localhost:7080/scalar. The API description it shows requires authentication, so log in to the web interface in the same browser first.
For example the endpoint /api/v1/activated (e.g. GET http://localhost:7080/api/v1/activated) returns a JSON encoded boolean value of whether the license is active or not. This endpoint is one of the first things the web interface checks to request a license to be entered.
GET /api/v1/version returns the server version as a JSON string, e.g. "1.0.0". Neither endpoint requires authentication.
The examples below use Host: localhost. Send the requests to the address and port the server listens on, 7080 by default.
Authentication
With some exceptions, nearly all API requests must be authenticated using valid credentials, and all API requests except the version and license checks require an active license. Each API request may be authenticated using one of the 2 following ways:
- Using a valid HTTP-only session cookie (used by the web interface, stored in the browser)
- Using a valid access token in the request header (retrieved by using the login endpoint)
The second method is recommended for network services that want to integrate with the central server.
Creating the first account
First, you must ensure that an account exists. This can be done through the web interface or by using the API endpoint to create a user. On initial startup the web interface prompts for the default admin account creation, which is the same as executing a request at this endpoint:
POST /api/v1/users/admin HTTP/1.1
Host: localhost
Content-Type: application/json
{"username":"<username>","password":"<password>"}
This request fails with 401 Unauthorized if an account already exists.
Logging in
To obtain the authentication token, you must use the /api/v1/users/login endpoint.
Note the useCookies=false parameter to prevent the server from setting a session cookie, and return an access token response instead. If set to true, the server returns an HTTP cookie intended for browsers instead.
POST /api/v1/users/login?useCookies=false HTTP/1.1
Host: localhost
Content-Type: application/json
{"username":"<username>","password":"<password>"}
The response will be of the following format:
{
"tokenType": "Bearer",
"accessToken": "<access token>",
"expiresIn": 3600,
"refreshToken": "<refresh token>"
}
Make sure to store both the accessToken and refreshToken values somewhere secure.
The string under accessToken represents the secure token that must be used in the Authorization header of every authenticated request. This token expires after 1 hour (expiresIn is in seconds).
A wrong username or password is answered with 401. After 5 failed attempts the account is locked for 5 minutes; while it is locked, the response is 400 and the errors.endDate field holds the time the lock ends.
Refreshing the access token
In order to avoid having to log in again after 1 hour, call the /api/v1/users/refresh endpoint with the previously received refreshToken, as such:
POST /api/v1/users/refresh HTTP/1.1
Host: localhost
Content-Type: application/json
{"refreshToken":"<refresh token>"}
The response is the same as for the login request. You will receive a new accessToken which expires in 1 hour and a new refreshToken which expires in 14 days. An expired or invalid refresh token is answered with 401; log in again in that case.
If the user is updated (e.g. a new password or roles) or deleted in the meantime, the refresh token is invalidated. You will be able to keep using the access token until it expires for endpoints that have nothing to do with user-specific information.
With a cookie type session, the server automatically renews the cookie when it is close to the expiration time, by returning the cookie along with a response to any API call where the cookie was passed, which the browser will know to replace.
Making authenticated requests
Let's say that you want to get the current status of all devices known by the server. For the request to go through, you need to include the Authorization header with the accessToken you received from the login or refresh token request.
The value of the Authorization header is the token type (Bearer) followed by a space and the accessToken value.
GET /api/v1/devices/states HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
Example response:
{
"01997046-fe18-78bf-8895-fed35b18b997": {
"connectionStatus": 4,
"observingWeight": true,
"weight": {
"statusBits": 112,
"alibiText": null,
"deviceId": "01997046-fe18-78bf-8895-fed35b18b997",
"significantDigits": 1,
"protocol": 1,
"status": 0,
"unit": 0,
"net": 93,
"gross": 161.6,
"tare": 68.600006,
"stable": true,
"inZeroRange": false,
"time": "2025-09-30T12:37:23.9714247+00:00"
}
}
}
Enumerations are sent as numbers:
| Field | Values |
|---|---|
connectionStatus |
0 disconnected, 1 error, 2 pending (waiting to reconnect), 3 connecting, 4 connected |
protocol, deviceProtocol |
0 RedBox, 1 ASCII |
unit |
0 kg, 1 lb |
status |
0 OK, any other value is an error code reported by the scale |
Permissions and errors
Endpoints that change data or send commands to scales require the Manager or Admin role; managing accounts and the license requires the Admin role. See Roles and accounts.
Errors are returned as JSON problem details, with the following status codes:
| Status | Meaning |
|---|---|
400 |
Invalid input |
401 |
Not authenticated, or wrong credentials |
403 |
Not permitted: the account lacks the required role, the license does not cover the function, or the ASCII command is not allowed |
404 |
The scale (or other resource) was not found |
409 |
Conflict, e.g. an RDC weight that was already uploaded |
422 |
The scale answered, but the result cannot be used: the weight is not stable, or the scale reported an error status |
504 |
The scale did not answer in time |
Scale management using the API
Most endpoints allowing you to get current scale status, historical data, update scales, require the use of the scale ID. This is a unique identifier the server randomly generates for each scale, and cannot be customized.
Therefore, the first step will usually be to list the available scales using the /api/v1/devices endpoint.
GET /api/v1/devices HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
The response will enumerate all available scales, except deleted ones:
[
{
"id": "01997046-fe18-78bf-8895-fed35b18b997",
"uidName": "6CCE8D",
"customId": "103",
"customName": null,
"networkLocation": "192.168.0.100",
"lastConnected": "2025-09-30T12:37:42.46625+00:00",
"updatedAt": "2025-09-22T07:15:24.824767+00:00",
"locationValid": true,
"managed": true,
"deleted": false,
"deviceProtocol": 1
},
{
"id": "01997047-2089-7f3b-9526-d8b8de694dbe",
"uidName": "14F290",
"customId": null,
"customName": null,
"networkLocation": "192.168.0.101",
"lastConnected": "2025-09-30T13:24:18.035218+00:00",
"updatedAt": "2025-09-22T07:15:33.641574+00:00",
"locationValid": true,
"managed": false,
"deleted": false,
"deviceProtocol": 0
}
]
About scale fields & names
The scale uidName (Scale unique name in the web interface) is the unique name of the scale as it was fetched from the scale using its respective protocol. It is also unique and cannot be changed.
The requirement for having and using a random unique id is because scales may also be added manually without ever having to connect to them, as such for these scales the uidName will always be null (e.g. scales intended to be used for RDC).
Scales can also be assigned a customName, which is nothing more than a user-defined name for the scale, for convenience. It appears in the web interface of the central server to more easily identify scales. This name does not have to be unique and may be changed at any time, no APIs require it to be sent.
Lastly, scales may also be assigned a customId which will be elaborated upon below.
locationValid is false when another scale has since been found at the same networkLocation. Weight requests and commands to a scale whose location is not valid are answered with 404.
Requesting weights
One of the most common use cases for the central server is to provide unified access to scales. The only prerequisite to access a scale using the API is that the scale is known by the server, either because it was auto-discovered or was added manually, and that the license includes the scale management feature. After obtaining the scale's id, you can request the current weight, regardless of protocol (ASCII/RedBox), using the endpoint /api/v1/devices/{id}/weight.
GET /api/v1/devices/01997046-fe18-78bf-8895-fed35b18b997/weight HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
The central server weight response includes all known weighing information in one message, with data on how to display the given weight. The exact format varies slightly between protocols. The RedBox weight response includes much more information: scale interval index, X/Y angles, totalization data, weigh in motion progress and some extra flags.
The RedBox protocol response includes everything in the ASCII response + additional fields, with the exception that the alibiText field is now the alibiNr: the alibi is always a number in the RedBox, while for ASCII it is possible to have any string, though it is usually numerical.
ASCII example:
{
"statusBits": 112,
"alibiText": null,
"deviceId": "01997046-fe18-78bf-8895-fed35b18b997",
"significantDigits": 1,
"protocol": 1,
"status": 0,
"unit": 0,
"net": 93,
"gross": 161.6,
"tare": 68.600006,
"stable": true,
"inZeroRange": false,
"time": "2025-09-30T14:34:31.3197938+00:00"
}
RedBox example:
{
"scaleNumber": 0,
"alibiNr": 0,
"wiMProgress": 0,
"canBeShown": true,
"safetyCriticalError": false,
"xAngle": -0.5827853,
"yAngle": 0.45657697,
"totalFinalized": false,
"totalNeedToSeeZero": false,
"totalBiggestScaleIntervalIndex": 0,
"totalNumberOfWeighings": 0,
"totalNet": 0,
"totalGross": 0,
"deviceId": "01997047-2089-7f3b-9526-d8b8de694dbe",
"significantDigits": 1,
"protocol": 0,
"status": 0,
"unit": 0,
"net": 1,
"gross": 1,
"tare": 0,
"stable": true,
"inZeroRange": false,
"time": "2025-09-30T14:46:11.8676344+00:00"
}
POST /api/v1/devices/{id}/save-current-weight (requires the Manager role) reads the current weight in the same way and stores it as a saved weight. It fails with 422 if the weight is not stable or the scale reports an error status.
Scale commands
Common commands
The following commands are supported for both ASCII and RedBox protocols. They require the Manager role and the scale management feature:
-
Set Zero: POST/api/v1/devices/{id}/zeroempty body
-
Automatic Tare: POST/api/v1/devices/{id}/auto-tareempty body
-
Manual tare: POST/api/v1/devices/{id}/manual-tarebody containing a JSON encoded floating point number, e.g.
12.5
If the scale answers with an error code, the request fails with 422.
Note about scale commands and weight requests
If the requested device is managed, the request is immediately processed using the active connection. If the device is not connected at that moment, the request waits for about 2 seconds before failing with 504.
If the device is not managed, the central server attempts to establish a connection to the device, then processes the request. Here the server waits at most 30 seconds for the connection to be established before failing with 504.
After the request is completed, the scale remains connected for another 30 seconds, with each subsequent request resetting this timer. The connection is closed when no request is made for 30 seconds.
ASCII specific commands
Devices using the ASCII protocol have the following additional commands:
-
ASCII Command: POST/api/v1/devices/{id}/ascii-commandbody containing the command name as a JSON string (e.g.
"GG"), allowed values are:GG,GN,GT,SZ,RZ,SR,RS,GP,GA,MN,MG,AN,AG. Other commands are refused with403. The response is the scale's answer. -
Reconfigure: POST/api/v1/devices/{id}/ascii-reconfigureempty body. This command re-fetches and saves the updated ASCII parameters from the scale. This is useful if scale parameters like the unit label change. Unlike with RedBox devices, the central server cannot detect these changes normally, and regularly fetching ASCII parameters may cause performance issues with the scale.
Weight history
The saved weights and weight updates can be read page by page:
- GET
/api/v1/devices/saved-weights: saved weights, requires the RDC or the data collection feature - GET
/api/v1/devices/weight-changes: weight updates, requires the data collection feature
Both return at most 1000 records per request. The /export variants (/api/v1/devices/saved-weights/export, /api/v1/devices/weight-changes/export) return the records as a CSV file, at most 100 000 per request. The filters (scales, time range, status, source and others) are query parameters, described at /scalar.
Uploading weights
Weights weighed elsewhere can be uploaded to the server and are stored as saved weights. These routes require the RDC feature. Whether they require authentication depends on the Require authentication for legacy routes setting (see Security).
- POST
/api/v1/devices/save-weight - POST
/api/v1/devices/save-weight/redbox: the same, with the additional RedBox fieldsinZeroRange,scaleNumber,totalNumberOfWeighings,totalNet,totalGross,xAngleandyAngle
POST /api/v1/devices/save-weight HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
Content-Type: application/json
{
"deviceId": "01997046-fe18-78bf-8895-fed35b18b997",
"alibi": "1234",
"significantDigits": 1,
"status": 0,
"unit": 0,
"net": 93,
"gross": 161.6,
"tare": 68.6,
"time": "2025-09-30T14:34:31+00:00",
"customFields": {"Product": "A12"}
}
deviceId is the scale's id. A status other than 0 is refused with 400, an unknown deviceId with 404. Without time, the time of receipt is used.
The RDC HTTP upload route is described under Legacy API.
Application settings
The application settings can be read with GET /api/v1/settings and changed with POST /api/v1/settings (requires the Manager role). The body contains only the settings to change; the response contains all settings. Settings the license does not allow are reset in the response.
POST /api/v1/settings HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
Content-Type: application/json
{"broadcastSelf": false}
| Setting | In the web interface |
|---|---|
receiveRdc, receiveRdcPort |
RDC server |
discoverRedBoxes |
Discover RedBox scales |
discoverAscii |
Discover ASCII scales |
broadcastSelf |
not shown, see Server discovery responder |
noMessageTimeoutMs |
Disconnect timeout |
reconnectLinearIntervalStepMs |
Reconnection time step |
maximumReconnectIntervalMs |
Reconnection maximum time |
enableDataCollection |
Data collection |
collectDeviceWeights |
Collect weight updates |
collectAppDeviceLogs |
Collect device-related application logs |
collectDeviceLogs |
Collect RedBox device logs |
logsRetentionTimeSeconds |
Application and device logs retention time |
weightRetentionTimeSeconds |
Device weight retention time |
requireAuthForScaleManagement |
Require authentication for legacy routes |
Unknown settings and values out of range are refused with 422.
Legacy API
Each scale may be assigned a Custom ID. This is a user-defined value that must be either null or unique. This identifier also appears next to the device name in the UI (preceded by a hash sign).
This can be used as a way to identify scales similar to customName (with the unique requirement), but it mainly exists for what we call the legacy APIs. These APIs match the requests and responses of the old RAVAS Integration Server (RIS) and RAVAS Data Collector (RDC):
- POST
/rest/scale/weight: upload a weight, as the RDC did over HTTP - GET
/rest/scale/{customId}/weight/gross: Get current gross weight - GET
/rest/scale/{customId}/weight/net: Get current net weight - GET
/rest/scale/{customId}/weight-alibi-nr/gross: Get gross with alibi - GET
/rest/scale/{customId}/weight-alibi-nr/net: Get net with alibi
Whether these routes require authentication depends on the Require authentication for legacy routes setting (see Security), enabled by default. When enabled, authenticate as for any other request.
Reading weights
The GET routes require the scale management feature. They only work with ASCII scales, found by their Custom ID, whose location is valid; any other scale is answered with 404. The weight/gross and weight/net routes accept a noMotion=true query parameter, which sends the scale's no-motion command (MG or MN instead of GG or GN). The alibi routes send AG or AN.
Example request and response
GET /rest/scale/103/weight/gross?noMotion=true HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
{
"timestamp": "2025-09-30 15:43:56.419",
"alias": "103",
"type": "GROSS_WEIGHT_NO_MOTION",
"weight": 162.4
}
The timestamp is the server's local time. The type field depends on the route:
| Route | type |
|---|---|
weight/gross |
GROSS_WEIGHT, or GROSS_WEIGHT_NO_MOTION with noMotion=true |
weight/net |
NET_WEIGHT, or NET_WEIGHT_NO_MOTION with noMotion=true |
weight-alibi-nr/gross |
GROSS_WEIGHT_NO_MOTION_WITH_ALIBI |
weight-alibi-nr/net |
NET_WEIGHT_NO_MOTION_WITH_ALIBI |
The alibi routes add the alibi number in an alibiNr field. If the scale answers with an error, or with something that cannot be read as a weight, the request fails with 422; if it does not answer in time, with 504.
Uploading weights over HTTP
POST /rest/scale/weight requires the RDC feature and stores the weight like a record received by the RDC service.
POST /rest/scale/weight HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
Content-Type: application/json
{
"scaleId": "103",
"operatorId": "7",
"sequenceNr": 15,
"weightUnit": "kg",
"grossWeight": 161.6,
"netWeight": 93,
"tareWeight": 68.6,
"alibiNumber": "1234",
"weighingDate": "2025-09-30",
"weighingTime": "15:43",
"totalWeighing": 0,
"totalWeight": 0,
"productId1": "",
"productId2": "A12",
"productId3": "",
"productId4": ""
}
scaleId,grossWeight,netWeightandtareWeightare required.scaleIdis matched against the scale'sCustom ID,Scale unique nameorid.weightUnitiskgorlb; anything other thanlbis stored as kg.weighingDatemay beyyyy-MM-dd,dd-MM-yyyyorMM-dd-yyyy(a date that fits both of the last two is read asdd-MM-yyyy),weighingTimeisHH:mm, both in the server's time zone. If they cannot be read, the time of receipt is used.productId1toproductId4are stored asField #1toField #4, skipping empty ones; in the example,A12is stored asField #2.
A successful upload is answered with:
{"statuscode": 200, "statusmessage": "OK"}
An unknown scaleId is answered with 404. A weight with the same sequenceNr and alibiNumber as one already stored for the scale is answered with 409 and not stored again.