Developers

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.

Authentication

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.

# Every request:
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.

# Get a token pair:
POST /api/token/
{ "username": "...", "password": "..." }

# Two-factor accounts also send "totp_code"
# Then, every request:
Authorization: Bearer <access_token>
Permissions

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.

Base URL & Rate Limits

The essentials

Base URL: https://your-vitrio-domain/api/v1/ # versioned, paginated — build on this
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
Endpoints

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.

MethodEndpointPurpose
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

curl "https://your-vitrio-domain/api/v1/inventory/?page_size=100" \
  -H "Authorization: Api-Key YOUR_KEY_HERE"
Webhooks

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.

POST https://your-endpoint
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", ... } }
# Verify a delivery (Python)
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.

EventWhen it is sent
purchase_request.approvedEvery approval step has signed off.
purchase_request.rejectedAn approver rejected the request.
purchase_request.orderedThe order was placed with a supplier (PO number assigned).
purchase_request.withdrawnThe request was withdrawn before delivery.
purchase_request.receivedThe full quantity has been received.
goods_receipt.acceptedA delivery passed inspection and became usable stock.
goods_receipt.rejectedA delivery failed inspection and was quarantined.
invoice.createdA supplier invoice was recorded.
invoice.paidA supplier invoice is now fully paid.
supplier.status_changedA supplier was activated, suspended or reinstated.
supplier.contract_expiringA supplier contract is about to end.
approval.escalatedAn approval waited too long and was escalated.
stock_alert.raisedLow stock, stock-out, expiry or overstock alert.
temperature_excursion.openedA reading outside the storage range opened an excursion.
temperature_excursion.resolvedThe excursion response was completed.
recall.initiatedA batch recall quarantined stock.
test.loggedA test result was logged and reagents were deducted.
specimen.status_changedA specimen moved to its next stage (collected, received, accepted, rejected, validated, reported...).
test_continuity.availability_overriddenSomeone manually overrode a test's availability.
capa.openedA corrective/preventive action was logged.
capa.closedA CAPA was closed after its effectiveness check.
sop.approvedA new SOP version came into force.
maintenance_ticket.openedA fault or service ticket was raised against equipment.
maintenance_ticket.closedA maintenance ticket was closed.
Sending data in

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.

POST /api/v1/ingest/temperature/
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.

Full Reference

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.