Developers
API guide & reference
Aliquora
aliquora.com
A practical guide to integrating with Aliquora's REST API — create and track samples, enter and verify results, and pull reference data from your own systems. Every endpoint and limit below reflects the live v1 API.
Document type
API guide & reference
Audience
Developers & integrators
Base URL
https://aliquora.com/api/v1
Overview
The Aliquora API is a JSON-over-HTTPS REST API. It lets you automate the lab workflows you already use in the app: registering samples, scheduling tests, entering and verifying results, and reading reference data such as test definitions, material types, projects, and clients. Every API key is scoped to the organization that owns it — keys only ever see and change data within their own tenant.
The current version is v1. All endpoints live under a single base URL:
https://aliquora.com/api/v1
You can confirm the live endpoint list at any time by calling GET /api/v1, which returns the API
name, version, and a complete list of routes. API access is available on plans that include the API feature —
see pricing for details.
Quick start. (1) In the app, go to Settings → API Access and create a key.
(2) Copy the rawKey — it is shown only once. (3) Call
GET /api/v1/whoami with the key to confirm it works, then start creating samples.
Authentication
Every request to /api/v1/* must include your API key as a bearer token in the
Authorization header:
Authorization: Bearer lk_your_key_here
API keys begin with the prefix lk_ followed by a long random string. Keys are stored only as a
one-way hash — Aliquora can never show you the full key again after creation, so store it securely (for example
in your secrets manager or environment variables). A request with a missing or invalid key returns
401 with a WWW-Authenticate: Bearer header. A request from a plan without API access
also returns 401.
Creating and managing keys
Keys are created in the app by an administrator (the system administrator or
administrator role) under Settings → API Access. Each key has a human-readable
name so you can tell your integrations apart. On creation, the API returns the plaintext key exactly once as the
rawKey field; afterwards only a masked keyPrefix is shown.
{
"id": 7,
"name": "Integration server",
"keyPrefix": "lk_3f9a2b1c...",
"createdBy": 13,
"createdAt": "2026-06-18T12:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null,
"rawKey": "lk_3f9a2b1c… ← shown only once"
} You can list your keys, see when each was last used, and revoke a key at any time from the same screen. Revoking a key takes effect immediately. Every key is scoped to your organization and can only read and write your tenant's data.
Verifying a key
curl https://aliquora.com/api/v1/whoami \
-H "Authorization: Bearer lk_your_key_here" GET /api/v1/whoami echoes back the key's organization and ids:
{
"ok": true,
"organizationId": 42,
"keyId": 7,
"userId": 13,
"version": "v1"
} Endpoints
The v1 endpoints, grouped by area. The discovery endpoint GET /api/v1 is always the authoritative, current list.
Identity
| Method | Path | Description |
|---|---|---|
GET | /api/v1 | Discovery — name, version, and the full endpoint list. |
GET | /api/v1/whoami | The calling key's organization, key id, and user id. |
Samples
| Method | Path | Description |
|---|---|---|
GET | /api/v1/samples | List samples (filterable, cursor-paginated). |
GET | /api/v1/samples/:id | Retrieve one sample with its scheduled tests. |
POST | /api/v1/samples | Create a sample and optionally schedule tests. |
PATCH | /api/v1/samples/:id | Update mutable fields (not workflow status). |
PATCH | /api/v1/samples/:id/status | Transition workflow status. |
POST | /api/v1/samples/receive | Bulk-receive a set of samples by id. |
POST | /api/v1/samples/:id/report | Mark a sample as reported (blocked if QC fails). |
GET | /api/v1/samples/:id/approvals | List approval records for a sample. |
Tests & results
| Method | Path | Description |
|---|---|---|
GET | /api/v1/sample-tests | List sample tests (filter by sample or status). |
PATCH | /api/v1/sample-tests/:id | Enter or update a result (409 if verified/locked). |
POST | /api/v1/sample-tests/:id/verify | Verify and lock a result. |
POST | /api/v1/sample-tests/bulk-results | Enter many results in one call. |
POST | /api/v1/instrument-uploads | AI extraction of results from an instrument file. |
PATCH | /api/v1/approval-records/:id | Update an approval record. |
Reference data
| Method | Path | Description |
|---|---|---|
GET | /api/v1/test-definitions | List test definitions (codes, units, spec limits). |
GET | /api/v1/material-types | List material/matrix types. |
GET | /api/v1/projects | List projects. |
POST | /api/v1/projects | Create a project. |
PATCH | /api/v1/projects/:id | Update a project. |
GET | /api/v1/clients | List clients. |
POST | /api/v1/clients | Create a client. |
PATCH | /api/v1/clients/:id | Update a client. |
GET | /api/v1/storage-locations | List storage locations. |
Working with samples
List samples
GET /api/v1/samples supports the filters status, materialTypeId,
projectId, trackingId, since and until (by received date),
plus the pagination parameters limit and cursor.
GET /api/v1/samples?limit=100&cursor=1042&status=received {
"data": [
{
"id": 1041,
"trackingId": "S-2026-001041",
"status": "received",
"materialTypeId": 3,
"projectId": 8,
"receivedAt": "2026-06-18T09:12:00.000Z"
}
],
"nextCursor": 1041,
"hasMore": true
} Create a sample
POST /api/v1/samples registers a sample and, if you pass testDefinitionIds, schedules
those tests in one call. Referenced ids (material type, project, test definitions) must belong to your
organization, or the call returns 400 invalid_reference. Projects that use a composite sample
identifier also require plantLocation. Creating a sample counts against your plan's monthly sample
allowance.
curl -X POST https://aliquora.com/api/v1/samples \
-H "Authorization: Bearer lk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"clientName": "Acme Water District",
"materialTypeId": 3,
"projectId": 8,
"collectionDate": "2026-06-18",
"priority": "normal",
"testDefinitionIds": [12, 15],
"notes": "Grab sample, intake basin"
}' Move a sample through its workflow
Status is changed only through the dedicated endpoint PATCH /api/v1/samples/:id/status (the general
PATCH /api/v1/samples/:id updates other fields but not status). Valid statuses are
pending, received, processing, completed, and
verified.
curl -X PATCH https://aliquora.com/api/v1/samples/1042/status \
-H "Authorization: Bearer lk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "status": "received" }'
To bring in a batch at once, use POST /api/v1/samples/receive with a
{ "sampleIds": [ ... ] } body. When results are complete and verified,
POST /api/v1/samples/:id/report marks the sample reported — this is blocked with
409 qc_failed if a QC gate has not been satisfied.
Entering results
List tests with GET /api/v1/sample-tests (filter by sampleId or status),
then enter a result with PATCH /api/v1/sample-tests/:id. Once a result is verified it is locked;
further edits return 409 test_verified_locked. Verify a result with
POST /api/v1/sample-tests/:id/verify.
For high-throughput entry, send many results in a single request:
curl -X POST https://aliquora.com/api/v1/sample-tests/bulk-results \
-H "Authorization: Bearer lk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"updates": [
{ "sampleTestId": 5001, "result": "7.2", "notes": "pH in range" },
{ "sampleTestId": 5002, "result": "1.4" }
]
}' AI instrument uploads
POST /api/v1/instrument-uploads accepts a raw instrument export as multipart form data
(file) and uses AI to extract results, matching them back to the right sample tests by tracking id
and test code. Optional fields: hint (free-text context), dryRun (preview matches
without writing), and confidenceThreshold (0–1). The response returns the proposed matches with a
per-row confidence score so you can review before committing. Because these calls run AI extraction, they are
rate-limited more tightly than other endpoints (see below).
curl -X POST https://aliquora.com/api/v1/instrument-uploads \
-H "Authorization: Bearer lk_your_key_here" \
-F "file=@run-2026-06-18.csv" \
-F "dryRun=true" \
-F "confidenceThreshold=0.8" Pagination
List endpoints use cursor-based pagination. Pass limit (default 50, maximum
500) and an optional cursor (the id to read after). Each response includes the page
of records under data, plus nextCursor and hasMore. To page through
everything, keep calling with cursor set to the previous nextCursor until
hasMore is false.
Rate limits
| Endpoint group | Limit |
|---|---|
| All endpoints (per API key) | 120 requests / minute |
| AI instrument uploads | 20 requests / minute |
Exceeding a limit returns 429 with { "error": "rate_limited" }. Build a short
backoff into your client and retry.
Errors
Most errors are returned as JSON with an error slug and a human-readable message, alongside
the appropriate HTTP status code. Some validation and plan-limit responses instead carry a code field
(for example SAMPLE_LIMIT_EXCEEDED) or a message only.
{
"error": "rate_limited",
"message": "Too many requests. Limit is 120/minute per API key."
} | Status | Common slug(s) | Meaning |
|---|---|---|
400 | invalid_body / invalid_reference / invalid_id | Malformed input, or a referenced id does not belong to your organization. |
401 | (WWW-Authenticate: Bearer) | Missing or invalid API key, or your plan does not include API access. |
403 | SAMPLE_LIMIT_EXCEEDED | A plan limit (e.g. your monthly sample quota) was reached. |
404 | not_found | The resource does not exist in your organization. |
409 | test_verified_locked / qc_failed | The record is locked (verified) or a QC gate blocked the action. |
429 | rate_limited | You exceeded the per-key request limit. Back off and retry. |
500 | internal | An unexpected server error. Safe to retry idempotent reads. |
Versioning & stability
The API is versioned in the path (/api/v1). We add new endpoints and optional fields without bumping
the version; any breaking change would ship under a new version path. The authoritative, always-current list of
routes is the discovery endpoint GET /api/v1 and the in-app API Access page.
Building an integration? Create a key under Settings → API Access and start
with GET /api/v1/whoami. If you need an endpoint we don't expose yet, or help mapping an
instrument feed, get in touch.
This document describes Aliquora product capabilities as of the date provided and is offered for evaluation purposes. It is not legal or regulatory advice and is not a warranty of compliance. Each organization is responsible for validating and confirming that the system meets its own regulatory obligations. Generated by Aliquora · aliquora.com