LabArchives API Reference#
This document summarises the LabArchives REST API endpoints used by NexusLIMS.
Official docs: LabArchives API Docs
Base URL pattern:
https://<your-instance>/api/<api_class>/<method>Response format: XML for all endpoints
Authentication#
Every request must include three authentication query parameters:
Parameter |
Description |
|---|---|
|
Access Key ID — obtained from LabArchives API settings |
|
Current Unix timestamp in milliseconds (string) |
|
URL-encoded, base64-encoded HMAC-SHA-512 signature (see below) |
Most endpoints also require uid (the authenticated user’s ID).
Signature Calculation#
The signature is computed over the concatenation of akid + method_path + expires,
keyed with the access password:
message = akid + method_path + expires_ms
sig = base64(HMAC-SHA-512(access_password, message))
sig_url = URL-encode(sig)
Where method_path is the method name only — no class prefix or leading slash,
e.g. tree_level (not notebooks/tree_level).
Python:
import base64, hashlib, hmac, time
from urllib.parse import quote
expires = str(int(time.time() * 1000))
msg = AKID + METHOD + expires
raw_sig = hmac.new(
ACCESS_PASSWORD.encode("utf-8"),
msg.encode("utf-8"),
hashlib.sha512,
).digest()
sig_b64 = base64.b64encode(raw_sig).decode("utf-8")
JavaScript (Bruno pre-request script):
const crypto = require('crypto');
const akid = bru.getFolderVar('AKID');
const password = bru.getFolderVar('ACCESS_PASSWORD');
const expires = String(Date.now());
const method = 'user_access_info';
const sig = crypto
.createHmac('sha512', password)
.update(akid + method + expires)
.digest('base64');
bru.setVar('expires', expires);
bru.setVar('sig', encodeURIComponent(sig));
// the "temporary password" for the user needs to be URI encoded also
bru.setVar('la_app_password_encoded', encodeURIComponent(bru.getRequestVar('la_app_password')));
Getting a user’s UID#
uid is a persistent identifier for the LabArchives user account. Obtain it once
via users/user_access_info (see below) and store it in NX_LABARCHIVES_USER_ID.
Note:
users/user_access_infoandutilities/institutional_login_urlsdo not requireuid— they use onlyakid,expires, andsig.
Error Responses#
All errors are returned as HTTP 200 with an XML body containing an <error> element:
<response>
<error>
<code>4504</code>
<msg>Invalid signature</msg>
</error>
</response>
Code |
Category |
Description |
|---|---|---|
|
Permission |
Insufficient permissions |
|
Permission |
Access denied |
|
Auth |
Expired request |
|
Auth |
Invalid akid |
|
Auth |
Invalid signature |
|
Auth |
Session expired |
|
Auth |
Invalid credentials |
|
Not Found |
Resource does not exist |
|
Server error |
Retry with exponential backoff |
NexusLIMS maps these to typed Python exceptions:
LabArchivesAuthenticationError, LabArchivesPermissionError,
LabArchivesNotFoundError, LabArchivesRateLimitError.
Rate Limiting#
LabArchives requires at least 1 second between API calls per their Terms of Service.
NexusLIMS enforces this automatically in LabArchivesClient._throttle().
For 5xx server errors, NexusLIMS retries up to 3 times with exponential backoff
(2 s, 4 s, 8 s).
Endpoints#
Authentication / Users#
GET users/user_access_info#
Exchange LabArchives login credentials for a uid and notebook list.
This is the first call to make when setting up a new integration — use the
returned uid for all subsequent requests.
Does not require
uidparameter.
Query parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
LabArchives email address |
|
Yes |
LabArchives app token / account password |
Response XML:
<response>
<user_info>
<uid>12345</uid>
<email>user@example.com</email>
<notebooks>
<notebook>
<nbid>67890</nbid>
<name>My Lab Notebook</name>
</notebook>
</notebooks>
</user_info>
</response>
NexusLIMS method: LabArchivesClient.get_user_info(login, password)
GET users/user_info_via_id#
Retrieve user information for a known uid.
Query parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
User ID to look up |
GET utilities/institutional_login_urls#
Returns institution-specific SSO login URLs.
Does not require
uidparameter.
Query parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
Notebooks#
GET notebooks/tree_level#
Get the child nodes (folders and pages) at one level of a notebook’s tree.
Use parent_tree_id=0 for the root level.
Query parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
User ID |
|
Yes |
Notebook ID |
|
Yes |
Parent node ID; |
Response XML:
<response>
<tree_items>
<tree_item>
<tree_id>101</tree_id>
<display_text>NexusLIMS Records</display_text>
<type>folder</type>
</tree_item>
<tree_item>
<tree_id>202</tree_id>
<display_text>My Experiment</display_text>
<type>page</type>
</tree_item>
</tree_items>
</response>
NexusLIMS method: LabArchivesClient.get_tree_level(nbid, parent_tree_id)
Returns a list of dicts with keys tree_id, display_text, and is_page.
POST notebooks/insert_node#
Create a new folder or page node in the notebook tree.
Query parameters (auth only):
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
User ID |
Form body (application/x-www-form-urlencoded):
Field |
Required |
Description |
|---|---|---|
|
Yes |
Notebook ID |
|
Yes |
Parent node ID ( |
|
Yes |
Name of the new node |
|
Yes |
|
Response XML:
<response>
<tree_item>
<tree_id>303</tree_id>
<display_text>My New Folder</display_text>
<type>folder</type>
</tree_item>
</response>
NexusLIMS methods: LabArchivesClient.insert_folder(nbid, parent_tree_id, name) /
LabArchivesClient.insert_page(nbid, parent_tree_id, name)
Returns the tree_id of the newly created node.
GET notebooks/notebook_backup#
Export a full backup of a notebook (XML or JSON format).
Query parameters:
Parameter |
Required |
Default |
Description |
|---|---|---|---|
|
Yes |
— |
Access Key ID |
|
Yes |
— |
Timestamp in ms |
|
Yes |
— |
HMAC-SHA-512 signature |
|
Yes |
— |
User ID |
|
Yes |
— |
Notebook ID |
|
No |
|
Return JSON instead of XML |
|
No |
|
Exclude file attachments |
Entries#
POST entries/add_entry_to_page#
Add a text or HTML entry to a notebook page.
Query parameters (auth only):
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
User ID |
Form body (application/x-www-form-urlencoded):
Field |
Required |
Default |
Description |
|---|---|---|---|
|
Yes |
— |
Notebook ID |
|
Yes |
— |
Tree ID of the target page |
|
Yes |
— |
HTML or plain-text content |
|
No |
|
Entry part type |
Response XML:
<response>
<entry>
<eid>9876</eid>
<page_tree_id>303</page_tree_id>
</entry>
</response>
NexusLIMS method: LabArchivesClient.add_entry(nbid, page_tree_id, entry_data, part_type)
Returns the eid of the created entry.
POST entries/add_attachment_to_page#
Upload a file attachment to a notebook page. The file content is sent as the
raw request body (Content-Type: application/octet-stream) — not multipart.
All other parameters are passed as query string parameters.
Query parameters:
Parameter |
Required |
Description |
|---|---|---|
|
Yes |
Access Key ID |
|
Yes |
Timestamp in ms |
|
Yes |
HMAC-SHA-512 signature |
|
Yes |
User ID |
|
Yes |
Notebook ID |
|
Yes |
Tree ID of the target page |
|
Yes |
Filename to use for the attachment |
|
No |
Caption displayed under the attachment |
Request body: Raw file bytes (Content-Type: application/octet-stream)
Response XML:
<response>
<entry>
<eid>9877</eid>
<page_tree_id>303</page_tree_id>
</entry>
</response>
NexusLIMS method: LabArchivesClient.add_attachment(nbid, page_tree_id, filename, data, caption)
Returns the eid of the created attachment entry.
Bruno note: The Bruno collection uses
body: filefor this request. Auth and metadata go in the query string; the local file path is set in thebody:file { src: ... }block.
NexusLIMS Upload Workflow#
NexusLIMS follows this sequence when exporting a session record:
1. get_tree_level(nbid, "0")
→ find or create "NexusLIMS Records" folder
2. get_tree_level(nbid, nexuslims_folder_id)
→ find or create "{instrument_pid}" sub-folder
3. insert_node(nbid, instrument_folder_id, "{YYYY-MM-DD} — {session_id}", is_folder=False)
→ create a new page for this session
4. add_entry(nbid, page_tree_id, html_summary)
→ upload HTML session summary
5. add_attachment(nbid, page_tree_id, filename, xml_bytes, caption)
→ attach the full XML record
6. Build URL: {base_url}/#/{nbid}/{page_tree_id}
If NX_LABARCHIVES_NOTEBOOK_ID is not configured, the upload targets the user’s
Inbox (nbid="0", page_tree_id="0"), skipping folder creation.
Bruno Collection Setup#
The Bruno collection is at api_tests/NexusLIMS/LabArchives/. Configure the
variables in folder.bru (the vars:pre-request block):
Variable |
Where to get it |
|---|---|
|
|
|
LabArchives API settings page |
|
LabArchives API settings page |
|
Run |
|
Visible in the notebook URL or from the |
Recommended first-run order:
Set
AKIDandACCESS_PASSWORDin the environmentRun
Authentication / GET user_access_info— copy the returneduidSet
UIDin the environmentSet
NOTEBOOK_IDfrom the notebook list in the response (or the notebook’s URL)Run
Notebooks / GET tree_levelto verify access
Each request has a pre-request script that computes the HMAC-SHA-512 signature automatically — no manual signature calculation required.
NexusLIMS Configuration Reference#
Setting |
Required |
Description |
|---|---|---|
|
Yes |
Root URL of the LabArchives instance (no |
|
Yes |
API Access Key ID ( |
|
Yes |
API signing password |
|
Yes |
Pre-authenticated user ID ( |
|
No |
Target notebook ( |
See also: nexusLIMS/utils/labarchives.py (API client) and
nexusLIMS/exporters/destinations/labarchives.py (export plugin).