API
The web interface does everything through the server's REST API, and other programs can use the same API. Its routes start with /api/v1/.
Every running server describes all its routes at /scalar, for example http://localhost:7080/scalar. Log in to the web interface in the same browser first; the description needs it. This page covers logging in and the most common requests.
Two routes need neither a login nor a license: GET /api/v1/activated returns whether a license is active, and GET /api/v1/version returns the server version, e.g. "1.0.0".
The examples use Host: localhost; send the requests to the address and port of the server, 7080 by default.
Authentication
Nearly all requests need a logged-in user, and all of them except the two above need an active license. The web interface uses a session cookie. Other programs log in for an access token and send it with every request.
Creating the first account
On a server without accounts, the first administrator account can also be created through the API, as the Welcome page does:
POST /api/v1/users/admin HTTP/1.1
Host: localhost
Content-Type: application/json
{"username":"<username>","password":"<password>"}
This fails with 401 once an account exists.
Logging in
POST /api/v1/users/login?useCookies=false HTTP/1.1
Host: localhost
Content-Type: application/json
{"username":"<username>","password":"<password>"}
useCookies=false asks for tokens instead of a cookie:
{
"tokenType": "Bearer",
"accessToken": "<access token>",
"expiresIn": 3600,
"refreshToken": "<refresh token>"
}
Keep both tokens somewhere safe. The access token is valid for an 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; until then the answer is 400, with the end of the lock in errors.endDate.
Refreshing the access token
When the access token expires, exchange the refresh token for new tokens:
POST /api/v1/users/refresh HTTP/1.1
Host: localhost
Content-Type: application/json
{"refreshToken":"<refresh token>"}
The answer is the same as for logging in: a new access token for an hour, and a new refresh token for 14 days. An expired or invalid refresh token is answered with 401, and so is a refresh after the user's password or roles changed; log in again then.
Making authenticated requests
Send the access token in the Authorization header, after Bearer. For example, the current state of all scales:
GET /api/v1/devices/states HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
{
"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 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 from the scale |
Permissions and errors
Changing data and sending commands to scales needs the Manager or Admin role, managing accounts and the license the Admin role (see Roles).
Errors come as JSON problem details:
| Status | Meaning |
|---|---|
400 |
Invalid input |
401 |
Not logged in, or wrong credentials |
403 |
Not allowed: the user lacks the role, the license lacks the module, or the ASCII command isn't allowed |
404 |
The scale or other resource doesn't exist |
409 |
Conflict, e.g. a weight that was already uploaded |
422 |
The scale answered, but the weight isn't stable or the scale reported an error |
504 |
The scale didn't answer in time |
Scales
Most routes take the scale's id, so start by listing the scales. Deleted scales are left out.
GET /api/v1/devices HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
[
{
"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: generated by the server, and never changes.uidName: theScale unique name, read from the scale.nullfor a scale that was added by hand and never connected.customName: a free name, shown in the web interface.customId: theCustom ID, unique when set, used by the RDC service and the legacy routes.locationValid:falseonce another scale has been found at the samenetworkLocation. Weight requests and commands to the scale are then answered with404.
Requesting weights
With the scale management module, the current weight of any known scale, ASCII or RedBox, is:
GET /api/v1/devices/01997046-fe18-78bf-8895-fed35b18b997/weight HTTP/1.1
Host: localhost
Authorization: Bearer <access token>
{
"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"
}
A RedBox scale answers with the same fields and more: the scale interval (scaleNumber), the tilt (xAngle, yAngle), the totals (total…) and the weigh-in-motion progress. Instead of alibiText and statusBits it has alibiNr, as a RedBox alibi is always a number.
POST /api/v1/devices/{id}/save-current-weight (Manager role) reads the weight the same way and stores it as a saved weight. It fails with 422 if the weight isn't stable or the scale reports an error.
A managed scale answers over its open connection; if it isn't connected at that moment, the request fails with 504 after about 2 seconds. For a scale that isn't managed, the server connects first, waiting up to 30 seconds, and stays connected until no request has come for 30 seconds.
Scale commands
These need the Manager role and the scale management module, and fail with 422 if the scale answers with an error:
| Command | Route | Body |
|---|---|---|
| Set zero | POST /api/v1/devices/{id}/zero |
empty |
| Automatic tare | POST /api/v1/devices/{id}/auto-tare |
empty |
| Manual tare | POST /api/v1/devices/{id}/manual-tare |
the tare as a JSON number, e.g. 12.5 |
ASCII scales also take:
- POST
/api/v1/devices/{id}/ascii-command, with the command as a JSON string, e.g."GG". Allowed areGG,GN,GT,SZ,RZ,SR,RS,GP,GA,MN,MG,ANandAG; others are refused with403. The answer is the scale's. - POST
/api/v1/devices/{id}/ascii-reconfigure, with an empty body, reads the scale's parameters again, as Reconfigure in the web interface does (see Device connections).
Weight history
The saved weights and weight updates are read a page at a time:
- GET
/api/v1/devices/saved-weights: saved weights, with the RDC or the data collection module - GET
/api/v1/devices/weight-changes: weight updates, with the data collection module
Both return up to 1000 records per request. Their /export routes return CSV files of up to 100 000 records. The filters are query parameters, described at /scalar.
Uploading weights
Weights weighed elsewhere can be uploaded as saved weights, with the RDC module. Whether these routes need a logged-in user depends on the Require authentication for legacy routes setting.
- POST
/api/v1/devices/save-weight - POST
/api/v1/devices/save-weight/redbox: the same, plus the 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; an unknown one is answered with 404. A status other than 0 is refused with 400. Without time, the time of receipt is used.
Application settings
GET /api/v1/settings reads the application settings, POST /api/v1/settings changes them (Manager role). Send only the settings to change; the answer has all of them. Unknown settings and values out of range are refused with 422.
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 |
Legacy API
These routes answer like the RAVAS Integration Server (RIS) and the RAVAS Data Collector (RDC) did, and find scales by their Custom ID:
- POST
/rest/scale/weight: upload a weight, as the RDC did over HTTP - GET
/rest/scale/{customId}/weight/gross: the current gross weight - GET
/rest/scale/{customId}/weight/net: the current net weight - GET
/rest/scale/{customId}/weight-alibi-nr/gross: the gross weight with the alibi number - GET
/rest/scale/{customId}/weight-alibi-nr/net: the net weight with the alibi number
Whether they need a logged-in user depends on the Require authentication for legacy routes setting, enabled by default.
Reading weights
The GET routes need the scale management module, and only work with ASCII scales whose location is valid; other scales are answered with 404. weight/gross and weight/net take noMotion=true, which sends the scale's no-motion command (MG or MN instead of GG or GN). The alibi routes send AG or AN.
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
}
timestamp is the server's local time. type 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 as alibiNr. When the scale answers with an error, or with something that isn't a weight, the request fails with 422; when it doesn't answer in time, with 504.
Uploading weights over HTTP
POST /rest/scale/weight needs the RDC module, and stores the weight like a record from 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 butlbis stored as kg.weighingDateisyyyy-MM-dd,dd-MM-yyyyorMM-dd-yyyy(a date that fits both is read asdd-MM-yyyy), andweighingTimeisHH:mm, both in the server's time zone. When they can't be read, the time of receipt is used.productId1toproductId4are stored asField #1toField #4, skipping empty ones: in the example,A12isField #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.