Connect your ERP, accounting, or lab equipment software
Vitrio's REST API covers inventory, purchasing, suppliers, alerts, equipment, QMS and the reporting records managers pull into spreadsheets and BI tools — plus signed webhooks that push events to your systems the moment they happen. It's the same API the Vitrio app itself runs on.
Two ways to authenticate
Every endpoint below requires one of these. There is no public/unauthenticated read access, since this is per-company operational data.
API Key — recommended for integrations
For systems that can't hold a user session or refresh a JWT: an ERP, accounting platform, BI tool or lab equipment feed. Generate one from Integrations → API Keys once signed in (shown once, never stored in plaintext). Choose Read-only for reporting and BI (it cannot create, change or delete anything), and set an expiry if the key is for a contractor or a trial. A key stops working the moment it expires, is revoked, or the person who made it is deactivated.
Authorization: Api-Key <your-key>
JWT Bearer Token
For a first-party client that can log a user in and refresh a token: mobile apps, custom internal tooling.
POST /api/token/
{ "username": "...", "password": "..." }
# Two-factor accounts also send "totp_code"
# Then, every request:
Authorization: Bearer <access_token>
The API follows the account's role
A token or API key can do exactly what the person who owns it can do in the app. A Viewer can read but not change anything; a Technician can log usage, adjust stock and raise issues but not edit master data; Lab Admins and Managers manage items, test types, equipment and QMS records. Supplier, doctor and front-desk portal accounts have no REST API access. A request outside the role's permissions returns 403. Stock quantity can't be edited directly — send a stock adjustment, which is logged and, if large, approved by a second person.
The essentials
Legacy: https://your-vitrio-domain/api/ # original un-versioned paths, unchanged (plain lists)
# Every list under /api/v1/ is paginated:
GET /api/v1/inventory/?page_size=200&page=2 # {count, next, previous, results}; up to 1000 per page
# Incremental sync: only rows created or changed after a moment
GET /api/v1/invoices/?modified_after=2026-10-01T09:30:00Z
# Rate limits (per DEFAULT_THROTTLE_RATES)
Unauthenticated: 60 requests / minute
Authenticated: 300 requests / minute
Login/auth: 10 requests / minute
What's available
Every endpoint below is scoped to your own company's data automatically. It's the same tenant isolation the Vitrio app itself relies on. Full request/response schemas are in the interactive docs.
| Method | Endpoint | Purpose |
|---|---|---|
| GET/POST | /api/inventory/ | Inventory items: list, create, update stock levels |
| POST | /api/log-consumption/ | Log test-based consumption (auto-deducts inventory) |
| POST | /api/log-operational-usage/ | Log general/operational usage (auto-deducts inventory) |
| GET/POST | /api/purchase-requests/ | Purchase requests and their approval status |
| GET/POST | /api/suppliers/ | Suppliers, scorecards, and contact details |
| GET | /api/alerts/ | Active stock alerts (low stock, expiring soon, overstock) |
| GET/POST | /api/equipment/ | Equipment records and predictive maintenance risk |
| GET/POST | /api/maintenance-tickets/ | Maintenance tickets |
| GET/POST | /api/sops/, /api/capas/ | SOP register and CAPA records (approve / close through their actions) |
| GET | /api/specimens/ | Specimens and every stage timestamp |
| GET | /api/goods-receipts/, /api/invoices/, /api/budgets/ | Deliveries and their inspection result, supplier invoices, budgets (finance roles) |
| GET | /api/hmo-claims/ | HMO claims and their payment status (finance roles) |
| GET | /api/storage-locations/, /api/temperature-readings/, /api/temperature-excursions/ | Cold-chain configuration, readings and excursion responses |
| GET | /api/stock-counts/, /api/recalls/, /api/waste-disposals/ | Stocktakes, recalls and waste disposal |
| GET | /api/qc-levels/, /api/qc-results/ | Quality-control levels and results |
| GET | /api/dashboard/stats/ | Summary counts used by the Vitrio dashboard itself |
The reporting resources are read-only on purpose: those records are written through screens that enforce approvals, quarantine and the audit trail, and the API never offers a way around them. Patient details are never part of any resource.
Safe retries: Idempotency-Key
Add an Idempotency-Key: <unique string> header to any POST, PUT, PATCH or DELETE. If your connector times out and tries again with the same key, Vitrio returns the first response (marked Idempotent-Replay: true) instead of creating the record a second time. Keys are remembered for 24 hours and are private to the key or login that sent them; reusing a key with a different body returns 422.
Example request
-H "Authorization: Api-Key YOUR_KEY_HERE"
Get told the moment something happens
Subscribe a URL under Integrations → Webhooks, tick the events you want, and Vitrio POSTs a signed JSON message to it. Pair this with Zapier, Make or n8n to connect Vitrio to thousands of other tools without writing code.
X-Vitrio-Event: purchase_request.ordered
X-Vitrio-Event-Id: 7b1c... # same id on every retry — use it to ignore duplicates
X-Vitrio-Timestamp: 1791158013
X-Vitrio-Signature-V2: sha256=<HMAC-SHA256(secret, timestamp + "." + raw_body)>
{ "id": "7b1c...", "type": "purchase_request.ordered", "created": "2026-10-05T12:00:00Z",
"data": { "purchase_request_id": 42, "po_number": "PO-2026-00042", ... } }
import hmac, hashlib, time
def verify(secret, raw_body, timestamp, signature_header):
if abs(time.time() - int(timestamp)) > 300: return False # too old: possible replay
expected = "sha256=" + hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
Reliability: a delivery that fails (your server is down or answers with an error) is retried up to 5 times, after about 5 minutes, 30 minutes, 2, 6 and 24 hours. Every attempt is recorded in the delivery log, where you can see why one failed and resend it, and a Send test event button checks your endpoint before you rely on it. A slow or failing endpoint never slows down the person using Vitrio.
| Event | When it is sent |
|---|---|
purchase_request.approved | Every approval step has signed off. |
purchase_request.rejected | An approver rejected the request. |
purchase_request.ordered | The order was placed with a supplier (PO number assigned). |
purchase_request.withdrawn | The request was withdrawn before delivery. |
purchase_request.received | The full quantity has been received. |
goods_receipt.accepted | A delivery passed inspection and became usable stock. |
goods_receipt.rejected | A delivery failed inspection and was quarantined. |
invoice.created | A supplier invoice was recorded. |
invoice.paid | A supplier invoice is now fully paid. |
supplier.status_changed | A supplier was activated, suspended or reinstated. |
supplier.contract_expiring | A supplier contract is about to end. |
approval.escalated | An approval waited too long and was escalated. |
stock_alert.raised | Low stock, stock-out, expiry or overstock alert. |
temperature_excursion.opened | A reading outside the storage range opened an excursion. |
temperature_excursion.resolved | The excursion response was completed. |
recall.initiated | A batch recall quarantined stock. |
test.logged | A test result was logged and reagents were deducted. |
specimen.status_changed | A specimen moved to its next stage (collected, received, accepted, rejected, validated, reported...). |
test_continuity.availability_overridden | Someone manually overrode a test's availability. |
capa.opened | A corrective/preventive action was logged. |
capa.closed | A CAPA was closed after its effectiveness check. |
sop.approved | A new SOP version came into force. |
maintenance_ticket.opened | A fault or service ticket was raised against equipment. |
maintenance_ticket.closed | A maintenance ticket was closed. |
Let sensors and automations post readings
A temperature logger, a Wi-Fi sensor or a Zapier/Make/n8n step can post readings straight into Vitrio. Each one is judged against the storage location's range, opens a temperature excursion if it is out, and alerts your team exactly like a reading typed in by hand. Use an API key with read-and-write access, and an Idempotency-Key so a retried post is never counted twice.
Authorization: Api-Key YOUR_KEY_HERE
Idempotency-Key: fridge1-2026-10-05T14:30
{ "location": "Fridge 1", "value": 4.2, "recorded_at": "2026-10-05T14:30:00Z" }
# or up to 100 at once, each judged on its own
{ "readings": [ { "location": "Fridge 1", "value": 4.2 }, { "location": "Freezer A", "value": -19.5 } ] }
Tests can be logged the same way from an analyser, LIS or automation: POST /api/v1/log-consumption/ with a test_type, a quantity_tests and an idempotency_key. Vitrio deducts the reagents, applies expiry and batch rules, and records it in the audit trail.
location is the exact name or the id of an active storage location. recorded_at is optional and lets a device report a reading it took while offline (up to 7 days old, never in the future). The answer lists a result for every reading, including why one was rejected.
Every field, every response shape
This page covers the essentials. For the complete, always-current schema of every endpoint, use the interactive documentation, generated directly from the running API.