SDK installation
The UniteLabs SDK provides Python access to connected devices and platform APIs. This guide creates a project, installs the SDK packages, configures client credentials, and sends a first API request. It assumes you have completed Set up your development machine. For endpoint details, see the REST API reference.
Prerequisites
UniteLabs requires Python 3.10 or newer. It is platform independent and works equally on Linux, macOS and Windows.
Some steps require authentication, therefore you need:
- UniteLabs Artifactory Access
A username and password to install UniteLabs Python packages. UniteLabs packages are not published to PyPI — they are hosted in a private GitLab package registry. This is separate from GroundControl and the Platform; it is simply where the Python packages live.
- Username: 32 characters separated by dashes.
Example:56ae938f-484c-41cc-ae54-e4f9b8814fb7 - Password: 22 characters separated by dashes.
Example:ahjt-Lk-e1swOPZcWYYGh-mKJ
- Username: 32 characters separated by dashes.
- UniteLabs Client Credentials
Client ID and secret to authenticate connections made from your local SDK installation (your code/client) to the UniteLabs API (the platform).
- Client ID: A custom username with variable length.
- Client Secret: 32 characters without separators.
Example:YT1a2HFEoi8tiAwl6bv127Tqp0ZXDSru - Tenant Base URL: the web address of your tenant's API.
Example:https://api.<your-tenant>.unitelabs.io/ - Tenant Auth URL: the sign-in endpoint of your tenant, including the realm ID.
Example:https://auth.<your-tenant>.unitelabs.io/realms/<tenant-id>/protocol/openid-connect/
All of these come from UniteLabs. If you are missing one, the Get access page lists who to ask.
Install Packages
We recommend installing the UniteLabs SDK using a Python virtual environment manager such as uv, Poetry, or venv. All packages are provided in a private package registry which requires configuration and authentication.
The examples below install unitelabs-liquid-handling. This package includes the Liquid Handling SDK, while the labware library unitelabs-labware and core UniteLabs SDK (unitelabs-sdk) typically need to be installed as well. See the parts of the system for the full breakdown.
Uv is a tool that manages dependencies, maintains a lockfile for reproducible installations, manages your virtual environment and can build packages for distribution.
If you have not used uv before, you can follow any of the options for installation in the official uv installation instructions.
1. Prepare uv
Uv reads the UniteLabs Artifactory Access from a user's .netrc file. Set it up as described in Set up registry access. See the
official uv documentation for alternatives.
2. Setup Project
uv init --package my-app
cd my-app
3. Install UniteLabs
uv add unitelabs-liquid-handling \
--index unitelabs=https://gitlab.com/api/v4/groups/1009252/-/packages/pypi/simple
The example below also uses python-dotenv. It lives on public PyPI, so it must not go through the private index:
uv add python-dotenv
Poetry is a tool for dependency management and packaging in Python. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. Poetry offers a lockfile to ensure repeatable installs, and can build your project for distribution.
If you have not used poetry before, you can follow any of the options in the
official Poetry installation instructions.
1. Prepare Poetry
When poetry is available (try poetry -V in your terminal), you need to provide the UniteLabs Artifactory Access for poetry to be able to install the required dependencies. Optionally, we suggest to configure poetry to create the Python virtual environment within your project folder.
poetry config http-basic.unitelabs <username> <password>
poetry config virtualenvs.in-project true
2. Setup Project
poetry new my-app --src
cd my-app
3. Install UniteLabs
poetry source add --priority=supplemental unitelabs \
https://gitlab.com/api/v4/groups/1009252/-/packages/pypi/simple
poetry add --source unitelabs unitelabs-liquid-handling
The example below also uses python-dotenv. It lives on public PyPI, so it must not go through the private index:
poetry add python-dotenv
Venv allows you to manage separate package installations for different projects. It creates a "virtual" isolated Python installation.
1. Prepare pip
Pip reads the UniteLabs Artifactory Access from a user's .netrc file. Set it up as described in
Set up registry access. See the
official pip documentation for alternatives.
2. Setup Project
mkdir my-app
cd my-app
python -m venv .venv
.venv/bin/pip install -U pip
3. Install UniteLabs
.venv/bin/pip install unitelabs-liquid-handling \
--index-url https://gitlab.com/api/v4/groups/1009252/-/packages/pypi/simple
The example below also uses python-dotenv. It lives on public PyPI, so it must not go through the private index:
.venv/bin/pip install python-dotenv
Authenticate Client
You need to authenticate your UniteLabs client to access the UniteLabs API on your behalf. We suggest to use
python-dotenv to load the UniteLabs Client Credentials from a .env file in
the root of your project.
BASE_URL=https://api.<your-tenant>.unitelabs.io/
AUTH_URL=https://auth.<your-tenant>.unitelabs.io/realms/<tenant-id>/protocol/openid-connect/
CLIENT_ID=<client-id>
CLIENT_SECRET=<client-secret>
BASE_URL contains neither the tenant UUID nor a /v1 suffix; the SDK appends /v1 itself. A 404 on /v1/secrets or /v1/workflows means the path is doubled.Security note:
When using version control, make sure to exclude the .env file by e.g. adding it to the .gitignore file.
Send Your First Request
The SDK provides both asynchronous and synchronous clients. Choose based on your application's needs and personal preference:
- AsyncApiClient (recommended): For modern async/await code, better performance with concurrent operations
- SyncApiClient: For simple scripts or blocking code where async is not needed
import asyncio
from unitelabs.sdk import AsyncApiClient
from dotenv import load_dotenv
async def main():
# Async example (recommended)
client = AsyncApiClient()
connectors = await client.list_services()
for connector in connectors:
print(connector.name)
if __name__ == "__main__":
load_dotenv()
asyncio.run(main())
from unitelabs.sdk import SyncApiClient
from dotenv import load_dotenv
def main():
# Synchronous example
client = SyncApiClient()
connectors = client.list_services()
for connector in connectors:
print(connector.name)
if __name__ == "__main__":
load_dotenv()
main()
Run the script to verify your credentials and confirm the SDK can reach the platform. It should print the names of your connected instruments. This is just a smoke test; in real projects your entry point will vary.
Run the package's __main__.py file with:
uv run python -m my_app
poetry run python -m my_app
.venv/bin/python -m my_app
Troubleshooting
- Packages download from public PyPI instead of the private registry, or the install fails with 302 or 401: the
.netrcfile is not being picked up. Check the file permissions (chmod 600), the file location, and that it has no Windows line endings. - 404 on
/v1/secretsor/v1/workflows: theBASE_URLcontains the tenant UUID or a/v1suffix. Remove both; the SDK appends/v1itself. - 401 when running the first request:
CLIENT_IDorCLIENT_SECRETis wrong, or theAUTH_URLmisses the realm part.
Versions
The installation defaults to the latest version. Updates on versions and the corresponding changelogs are posted in the Technical Reference Section. If a defined version is required or needs to be locked, it must be explicitly defined using the PEP 440 Version Specifier(==, !=, <, >, <=, >, >=) in the pyproject.toml.
[project]
requires-python = ">=3.10,<4.0"
dependencies = [
"unitelabs-liquid-handling~=0.11.0",
"python-dotenv",
]
We recommend pinning explicit versions for workflows you plan on running in production. The installed version can be checked using __version__:
from unitelabs import labware, liquid_handling, sdk
if __name__ == "__main__":
print(sdk.__version__)
print(labware.__version__)
print(liquid_handling.__version__)
Run the file as explained above.
Note on client types:
Clientfromunitelabs.sdkis deprecated- Use
AsyncApiClient(recommended) for async/await patterns - Use
SyncApiClientfor synchronous/blocking code - Both clients provide the same methods - the only difference is async vs sync execution
IDE Integration
VSCode
{
"recommendations": ["ms-python.python"]
}
{
"python.defaultInterpreterPath": ".venv/bin/python",
"python.terminal.activateEnvironment": false
}
Jupyter Notebooks
ipykernel as a dev dependency and run SDK calls interactively in notebook cells — all async methods work via await in Jupyter without an explicit asyncio.run() wrapper.uv add --dev ipykernel
Next steps
Your first request already listed the connected instruments. Calling a connector shows how to inspect one and call its actions.