All documents

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

MethodPathDescription
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

MethodPathDescription
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

MethodPathDescription
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

MethodPathDescription
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 groupLimit
All endpoints (per API key)120 requests / minute
AI instrument uploads20 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."
}
StatusCommon slug(s)Meaning
400invalid_body / invalid_reference / invalid_idMalformed 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.
403SAMPLE_LIMIT_EXCEEDEDA plan limit (e.g. your monthly sample quota) was reached.
404not_foundThe resource does not exist in your organization.
409test_verified_locked / qc_failedThe record is locked (verified) or a QC gate blocked the action.
429rate_limitedYou exceeded the per-key request limit. Back off and retry.
500internalAn 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