UniteLabs SDK & REST API
The UniteLabs UniteLabs SDK and REST API expose the same connector model: services (connectors), modules (features), and actions (commands and properties). Each section below shows both approaches side by side.
Prerequisites
- Access to the UniteLabs platform
- An environment with an installed SDK — see Installation
- A connector deployed and connected to your tenant (the thermocycler demo works for these examples)
- Access to the UniteLabs platform
- API credentials: your tenant ID, client ID, and client secret: ask your UniteLabs contact if you don't have these
- A connector deployed and connected to your tenant
Authentication
The UniteLabs SDK handles authentication automatically using environment variables. For the REST API you need a Bearer token.
The SDK reads credentials from environment variables. Set them in your .env file:
BASE_URL=your-tenant-base-url
AUTH_URL=your-authentication-url
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret
Then instantiate the client — no token handling required:
from unitelabs.sdk import AsyncApiClient
client = AsyncApiClient()
Request a Bearer token via OAuth2 client credentials:
curl -X POST "https://auth.unitelabs.io/realms/{tenant-id}/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id={client-id}&client_secret={client-secret}"
Store the token and set your base URL for subsequent requests:
TOKEN="<access_token from response>"
BASE_URL="https://api.unitelabs.io/{tenant-id}/v1"
List connectors
Retrieve all connectors connected to your tenant.
services = await client.list_services()
print(services)
(Thermocycler(client=..., id='daa46515-49bc-4a7d-944f-369732edde2e', name='Thermocycler'),)
curl "$BASE_URL/services" \
-H "Authorization: Bearer $TOKEN"
[
{
"id": "daa46515-49bc-4a7d-944f-369732edde2e",
"name": "Thermocycler",
"category": "thermocycler"
}
]
Get a specific connector
Look up a connector by name or ID.
By name:
thermocycler = await client.get_service_by_name(name="Thermocycler")
print(thermocycler.id)
print(thermocycler.name)
By ID:
thermocycler = await client.get_service(service_id="daa46515-49bc-4a7d-944f-369732edde2e")
curl "$BASE_URL/services/daa46515-49bc-4a7d-944f-369732edde2e" \
-H "Authorization: Bearer $TOKEN"
Explore modules (features)
A connector's modules are its features — logical groupings of related actions.
print(thermocycler.modules.keys())
dict_keys(['sila_service', 'temperature_controller', 'door_controller'])
curl "$BASE_URL/services/daa46515-49bc-4a7d-944f-369732edde2e/modules" \
-H "Authorization: Bearer $TOKEN"
[
{ "id": "...", "name": "temperature_controller" },
{ "id": "...", "name": "door_controller" }
]
Explore actions
Each module exposes actions: the individual commands and properties you can call.
print(thermocycler.temperature_controller.actions.keys())
dict_keys(['get_target_temperature', 'subscribe_current_temperature', 'set_target_temperature'])
Check the type of an action (PROPERTY, COMMAND, or SENSOR):
print(thermocycler.temperature_controller.get_target_temperature.type)
# PROPERTY
List all actions for a module:
curl "$BASE_URL/modules/{moduleId}/actions" \
-H "Authorization: Bearer $TOKEN"
Get detailed info (parameters, response schema) for a specific action:
curl "$BASE_URL/actions/{actionId}" \
-H "Authorization: Bearer $TOKEN"
Subscribe to live data
Observable properties (Sensors) and commands stream data continuously. Use subscriptions to receive values as they change.
async for temperature in thermocycler.temperature_controller.subscribe_current_temperature():
print(temperature) # prints each new reading as it arrives
Cancel the subscription by breaking out of the loop or using asyncio cancellation.
Create a subscription by passing the action ID and an optional polling interval (milliseconds):
curl -X POST "$BASE_URL/subscriptions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"action": "{actionId}",
"parameters": {},
"interval": 1000
}'
{
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"action": "{actionId}",
"source": "..."
}
Cancel the subscription when done:
curl -X DELETE "$BASE_URL/subscriptions/f47ac10b-58cc-4372-a567-0e02b2c3d479" \
-H "Authorization: Bearer $TOKEN"
Next steps
- Execute commands: read properties and call commands on the instrument from a script: Calling a Connector
- Liquid handling & robots: additional SDK packages for deck building and liquid transfers: Operate