Skip to content

Migration guide, release 0.5.0

Release 0.5.0 replaces the monitoring API server. The functional model does not change: same artworks, same monitorings, same events, same lifecycle. What changes is a small number of contract details, listed here so that an integration can be adapted in one pass rather than discovered at runtime.

This page is for the teams calling the API directly, the StaRT mobile application first of all.

The addresses keep their current form, with no version segment:

https://api.smach.science/artworks

The contract evolves compatibly, so a client keeps working as new fields and endpoints appear. Should a later release ever need an incompatible version, it will be asked for with an optional Api-Version request header. Without the header, a request is served as version 1, which is the contract described here. There is nothing to send today.

The API has its own portal, at the root of the API host: the reference of the whole API, every endpoint with its parameters and schemas, and getting-started guides.

Environment API portal Reference
Production api.smach.science api.smach.science/reference
Development api.dev.smach.science api.dev.smach.science/reference

Signing in with a SmaCH account of the environment lets you send requests from the page itself, with your own token and the X-Organization header of your choice. The OpenAPI description can be downloaded from the same page.

It replaces the Swagger UI of the previous server, which goes away with it.

  • Hosts. https://api.dev.smach.science and https://api.smach.science.
  • Authentication. OAuth2 against Keycloak, Bearer token, same client and scopes. The realm changes on the development environment only, see below.
  • Organization context. The X-Organization header, with the same resolution rules: optional for a member of a single organization, required beyond, free for a super-admin.
  • Resource paths and payloads. /artworks, /monitorings, /inventories, the event structure, the status values and the ISO 8601 date format are unchanged. The one exception is the format of the id field, see “Identifiers become UUIDs”.

Read from the application’s source code on 2026-10-13 (branch dev, last changed on 2026-07-09). The application calls five endpoints:

Endpoint Phase Changes
GET /me login same payload, served by another service, one role fixed, see below
GET /artworks?status=ready artwork selection pagination
GET /artworks/{reference} artwork detail none
POST /artworks/{reference}/monitorings setup unknown equipment refused, id format
POST /artworks/{reference}/monitorings/events start, events, stop none

It does not call the inventory, the event list nor the event stream, which the StaRT API workflow also describes. The changes to those endpoints below concern any other integration.

Release 0.5.0 asks nothing of the application as it stands. Three choices of this release exist for that reason, each one listed under its change below: the setup and the push keep answering 200, the position of a gateway is read from the label the application sends, and an error carries its text in message as well.

A successful POST now answers 201 Created with a Location header pointing at the created resource, instead of 200. The response body is unchanged.

Impact: none if the client treats any 2xx as a success, a code change if it compares the status to 200 exactly.

Exception, for now: the setup (POST /artworks/{reference}/monitorings) and the event push (POST /artworks/{reference}/monitorings/events) keep answering 200. The mobile application compares their status to 200 exactly, and on any other success it would do nothing. They move to 201 once a release of the application accepts it; the date will be given here beforehand.

A list endpoint returns 50 items by default, 200 at most, where the previous server returned the whole collection. The payload is still a plain JSON array, so nothing changes in parsing, but a caller that reads the array and stops will silently miss anything beyond the first page.

Two response headers carry the navigation:

  • Link (RFC 8288) with first, prev, next and last relations. Following next opaquely is the recommended way to walk a collection.
  • X-Total-Count, the total number of items matching the filters.

Request parameters: page (0-indexed), size, search, sort. They are documented per endpoint in the OpenAPI description.

Impact: none as long as a collection holds fewer than 50 items, then silent truncation. Following the Link header removes the problem for good.

A <resource>/count endpoint now answers {"count": 42}. It previously answered {"value": 42, "previous": null, "trend": null}, a shape meant for dashboard statistics.

Errors are returned as RFC 9457 problem details, with the application/problem+json content type and a detail field carrying the message.

The same text is also given in a message field, which is what the mobile application displays. detail is the field of the contract; message will be withdrawn once the application reads detail, announced here beforehand.

The inventory requires the administrator role

Section titled “The inventory requires the administrator role”

Reading /inventories/* now requires the administrator role in the organization, or a super-admin account. A member holding the viewer role receives a 403.

This matches the documented perimeter of the user roles: a viewer browses collections, artworks and their monitorings, and does not see the equipment. It has no effect on StaRT if the application signs in with an administrator or super-admin account, which is the documented usage.

The id of every resource becomes a UUID, for example 0198c5a0-7c3e-7b1a-9d2f-4e6a8b0c1d2e, where the previous server returned a 24-character hexadecimal string. It is still a JSON string.

This matters for monitorings and events, which have no other key: the id returned by a setup is what the start and stop events carry as source, and what /monitorings/{id} names. Artworks are still named by their reference and equipment by its identity, which do not change.

Impact: none if the client stores and sends back the id as an opaque string, a code change if it validates its length or its format. See also “Going to production” for the monitorings that exist at the time of the switch.

The equipment named at setup must exist in the inventory

Section titled “The equipment named at setup must exist in the inventory”

POST /artworks/{reference}/monitorings now answers 400 when a datalogger names a logger, a sensor or a gateway that the inventory of the organization does not hold. The message names the unknown equipment. The previous server accepted any value.

The comparison is exact: 8 and 08 are two different identities. The existing data shows why it matters. The mobile application names a logger in decimal (18, 8), a sensor as s followed by two hexadecimal digits (s12, s08) and a gateway on eight digits (01000001), while the inventory was entered by hand as 12, 08 and GWR-001. The devices do not carry a real IMEI yet.

The form the mobile application sends today becomes the identity, so nothing changes on its side. The inventory is aligned on it during the transfer, see “Going to production”. From 0.5.0 on, an equipment added to the inventory is entered in that same form, or the application will not find it at setup.

At setup, the position of a gateway (cabin or trailer) may be omitted. The labels the mobile application sends are understood, in English and in French: Cabin or Cabine for the cabin, trailer or Remorque for the trailer. Any other value, such as Non disponible, records the gateway without a position rather than refusing the setup.

An identity has no leading nor trailing space

Section titled “An identity has no leading nor trailing space”

Creating or updating a logger, a sensor, a gateway or a packaging whose identity starts or ends with a space answers 400. The previous server stored it as sent, which made two items look alike and a reference miss its target.

PUT /inventories/<kind>/{identity} answers 400 when the identity of the body differs from the one in the URL. The previous server wrote the identity of the body, which renamed the item under whatever referenced it.

DELETE /artworks/{reference} now removes the artwork with its monitorings and their events. The previous server removed the artwork alone and left the rest unreachable. Archiving (status: archived) stays the ordinary way to retire an artwork and keeps everything.

The deletion answers 409 while the artwork has a monitoring set up or in progress (standby or monitoring): that history is still being written.

Four rules the previous server did not hold. They concern the web application; the mobile application does not write artworks.

  • The organization of an artwork is the one the request is made for, never the one in the body. The previous server stored the body as sent.
  • PUT /artworks/{reference} answers 400 when the reference of the body differs from the one in the URL. An artwork is not renamed by an update.
  • standby and monitoring follow the monitoring of the artwork. A request that sets one of them, or moves an artwork out of one of them, answers 409; a creation accepts draft and ready only (400 otherwise). A PUT without a status keeps the stored one.
  • inclosure and crate must name a packaging the inventory of the organization holds, of that kind: an unknown identity, or a crate given as inclosure, answers 400 with a message naming it.

Deleting a logger, a sensor or a gateway that appears in a monitoring, even an ended one, and deleting a packaging still assigned to an artwork, answer 409 with a message naming what holds it. The web application already prevented it on its side; the rule now holds for every caller.

GET /me keeps its payload: the account, its organizations and the role held in each, all read from the token. Only the service answering it changes, from the monitoring API to the identity service. The host and the address are the same.

One value is answered differently, and it is a correction rather than a change of contract. The role field carries the realm-wide role, and it used to be filled with the first role the token happened to list. Keycloak does not promise an order there, so an account holding several could be reported as a viewer in one token and a super-admin in the next. It now reports the highest role held, which is what every caller already assumed. Nothing to adapt, unless an integration worked around the old behaviour.

Unchanged in the same payload: an organization the account belongs to without holding a role there appears in organizations and not in roles.

GET /me/organizations is dropped before being built. It appeared in the StaRT API workflow as a v1.0.0 addition for super-admin accounts and was never implemented, in any version. It has no caller to migrate.

What it was meant to solve is real, and answered elsewhere. A super-admin belongs to no organization, so their token lists none, and /me therefore returns an empty list for them. It also returns a super-admin flag, and an account carrying that flag reads the full list from GET /organizations, which already exists and is already restricted to super-admins. One case, one endpoint, rather than a third path to the same answer.

Note for completeness: a super-admin account may also be an explicit member of an organization, a residual situation in the directory. /me then lists that membership, since it reports what the token says and nothing else.

Keycloak realm, development environment only

Section titled “Keycloak realm, development environment only”

In place. The development environment has its own realm, smach-dev, so that test accounts and organizations no longer live alongside production ones. The token endpoint of the development environment is:

https://id.smach.science/realms/smach-dev/protocol/openid-connect/token

The client is still start. The development API accepts tokens of this realm only: a token of realms/smach gets a 401 there. Accounts are not shared between the two realms, so a development account is asked for separately.

Production keeps realms/smach, unchanged.

To fix in the mobile application, independently of this release

Section titled “To fix in the mobile application, independently of this release”

Found while reading the application’s source code (branch dev), in formatSensorsConfig (services/dataloggerBackground.js). Neither comes from release 0.5.0: the API sends the same values before and after it. They are listed here so they are fixed in the same pass.

The range is looked up in a table keyed ±2g, ±4g, ±8g and ±16g, and any other value silently becomes 2g. The API writes the range without the sign (2g, 4g, 8g, 16g), which is the form of the contract and the one the web application saves. The previous server already answered that form, and so does the new one.

As a result, a range other than 2g never reaches the device. Measured in production on 2026-10-19: of 72 monitorings, two were set up at 8g, both test transports in September 2026, and were most likely recorded at 2g. Their thresholds, written for an 8g scale, then stood for a quarter of the intended acceleration. This is deduced from the code and not read from the devices.

Fix: read both spellings, with and without ±, and refuse an unknown range rather than fall back.

The same table maps ±16g to 0x16 (22), where the frame description in the same file gives 0x10 for 16g. Once the lookup above is fixed, a 16g range would be sent to the device as an invalid value.

Done on 2026-10-20, in production and on the development environment.

  • All existing data is transferred, in production and on the development environment: artworks, monitorings, events and inventory. Nothing is sorted out nor dropped by the transfer.
  • Equipment identities are aligned on what the mobile application sends. Inventory loggers are re-keyed from hexadecimal to decimal (12 becomes 18) and gateways from their label to their eight digits (GWR-001 becomes 01000001), the former value moving to the name. Monitorings recorded before April 2026, which named their loggers in hexadecimal, are rewritten the same way with their events. Equipment that appears in a monitoring and nowhere in the inventory is added to the inventory, marked as imported.
  • Every monitoring receives a new id. Events follow their monitoring, so no history is lost. Consequence for the mobile application: a monitoring set up or started before the switch cannot be started or stopped after it, since the application holds the former id. The switch therefore takes place at a time when no monitoring is pending or in progress, agreed beforehand.
  • Links to /monitorings/<former id> saved from the web application stop working.

Answers to these determine whether anything has to change in the mobile application at all:

  1. Does the HTTP client treat any 2xx response as a success? Answered by the source code: the setup and the push compare the status to 200, which is why they keep it.
  2. Which account does the application sign in with during a setup: administrator, super-admin, or something else?
  3. Is the endpoint list above complete? Answered by the source code: five endpoints.
  4. Is the identity form the rule for every device? Answered by the source code: the logger is the device number, the sensor is s followed by that number in two hexadecimal digits, the gateway is the label the device reports.
  5. Is the id of a monitoring kept as an opaque string? Answered by the source code: yes, no format is checked.
Subject State
Endpoints called by StaRT read from the source code
201 on creation decided, setup and push excepted for now
Pagination decided
/count payload decided
Error format decided, with message for now
Inventory role decided
UUID identifiers decided
Unknown equipment refused at setup decided
Gateway position optional, read from the label decided
Identity form: the one the mobile application sends decided, confirmed by the source code
Trimmed identities decided
No rename through an update decided
Artwork deletion removes its history decided
Equipment in use cannot be deleted decided
Data transfer and production switch done on 2026-10-20
Development realm in place, smach-dev
API reference published on both environments, production since 2026-10-28