INVI is a transactional inventory ledger - a high-performance inventory management system (IMS) component designed for enterprises in fulfillment, logistics, and inventory domains. It provides a reliable API to solve complex inventory challenges and serves as the single source of truth for all inventory concerns in your organization.
Transactional Inventory Storage
- WHAT: Track all inventory items
- WHERE: Know exact locations of inventory
- HOW MUCH: Real-time quantity tracking
- WHY: Track purpose and history (sale, inspection, fulfillment, etc.)
Data Integrity & Reliability
- RESTful API: Modern HTTP-based API for easy integration with any system that can make HTTP requests
- PostgreSQL 17: Enterprise-grade relational database ensures ACID compliance and data durability
- Docker Containers: Portable, isolated deployment that runs consistently across development, staging, and production
INVI is a core inventory component, not a complete end-user application. It does not include:
- ❌ A user interface (UI)
- ❌ Order Management System (OMS) features
- ❌ Fulfillment Management System (FMS) features
- ❌ Warehouse Management System (WMS) features
INVI provides the foundational inventory ledger that you build your IMS and UI around. It integrates with other systems via its REST API, serving as the single source of truth for inventory.
- Docker and Docker Compose installed
- 2GB RAM available
- Internet connection to pull images
-
Create project directory with configuration files:
mkdir invi-ledger cd invi-ledger # Copy docker-compose.yml and .env.example from this repository # Then: cp .env.example .env # Edit .env and set POSTGRES_PASSWORD
-
Start the services:
docker compose up -d
-
Apply database migrations:
curl -X POST http://localhost:8080/api/admin/upgrade
-
Verify it's running:
curl http://localhost:8080/api/admin/version
-
Access the API:
- API: http://localhost:8080
- Interactive API reference (Scalar): http://localhost:8080/scalar/v1 (only available when
ENVIRONMENT=Development) - OpenAPI document: http://localhost:8080/openapi/v1.json (only available when
ENVIRONMENT=Development)
docker compose downTo also remove data:
docker compose down -v- INVI Ledger API: RESTful API for inventory management
- PostgreSQL 17: Database for persistent storage
- Database migrations: Apply via Admin API after first startup
GET /api/inventoryitems- List all inventory itemsGET /api/inventoryitems/{primaryId}- Get specific item by IDPOST /api/inventoryitems- Create new itemPUT /api/inventoryitems/{primaryId}- Update item ID (rename)DELETE /api/inventoryitems/{primaryId}- Delete item (fails if item has assignments)
Note: See Understanding primaryId to learn why it's called primaryId and how to work with multiple identifier types (SKUs, GTINs, barcodes).
Locations represent where inventory is stored. They form a hierarchical tree structure similar to a file system.
Location Paths:
- All paths start from the root:
~ - Child locations use
/as separator:~/Warehouse-A/Aisle-5/Shelf-3 - Like directories: a location can contain both inventory and child locations
- Queries can target entire subtrees (e.g., "all inventory in Warehouse-A and its children")
Physical or Logical:
- Locations don't have to be physical places
- Can represent logical groupings:
~/Suppliers/Acme,~/Categories/Electronics/Phones - Mix and match:
~/Warehouse-A/Quarantineor~/Virtual/Reserved-For-VIP-Customers
Operations:
-
GET /api/locations?fromPath={path}&recursive={true|false}- List locationsfromPath: Starting point in the tree (e.g.,~/Warehouse-A)recursive=true: Returns all descendantsrecursive=false: Returns only direct children
-
GET /api/locations/stat?path={path}- Get specific location by exact path -
POST /api/locations- Create new location- Requires parent path and primary name
- Example: Parent
~/Warehouse-A, NameAisle-5→ Creates~/Warehouse-A/Aisle-5
-
DELETE /api/locations- Delete location (requires path in request body)- Fails if location has children or inventory
Assignments represent how much inventory is allocated for different purposes at each location.
Understanding Assignment Primary ID:
Each assignment can have an optional assignmentPrimaryId that identifies why the assignment exists or what specific entity it's associated with:
- For generic inventory: Use
null- e.g.,{kind: "stock", primaryId: null}represents general available stock - For order-specific inventory: Use order ID - e.g.,
{kind: "reserved", primaryId: "ORDER-12345"}reserves inventory for a specific order - For batch/lot tracking: Use batch ID - e.g.,
{kind: "stock", primaryId: "BATCH-2024-A"}tracks inventory by batch - For shipment tracking: Use shipment ID - e.g.,
{kind: "shipped", primaryId: "CUST-001"}tracks what was shipped to whom
Important Matching Behavior:
- When querying or changing assignments,
primaryIdfilters are exact match only primaryId: nullmatches ONLY assignments with null primaryId (not "any primaryId")primaryId: "BATCH-A"matches ONLY assignments with that exact value- For automatic batch selection (FIFO/FEFO), use
sortKeyinstead ofprimaryId
Query Operations:
-
POST /api/assignments/total- Query aggregated inventory amounts- Sums inventory across an entire location tree (e.g., "Total reserved inventory in all warehouses")
- Groups by item and assignment kind
- Can filter by item, assignment kind, or assignment ID
-
POST /api/assignments/detailed- Query inventory with location breakdown- Shows inventory amounts at each specific location within a tree
- Includes location paths, assignment IDs, and sort keys for each assignment
- Useful for understanding inventory distribution
Transaction Operations:
-
POST /api/assignments/set- Set assignment amounts (allocate, reserve, etc.)- Sets exact amounts or applies deltas (add/subtract)
- Atomic: either all changes succeed or none do
- Prevents negative inventory
- Use cases: Reserve inventory for orders, allocate to fulfillment, etc.
-
POST /api/assignments/change- Transfer inventory between assignment kinds- Moves inventory from source to destination (e.g., "Available" → "Reserved")
- Processes across location trees using lowest sort-key assignments first
- Atomic: either all changes succeed or none do
- Commands within a batch are independent — each sees the initial inventory state, not effects of other commands in the same request
- Use cases: Fulfill orders, move from quarantine to available, etc.
-
POST /api/assignments/cycle-count- Reconcile physical counts- Compares physical count with system total at a location
- Set
allowAutoResolution: trueto auto-resolve shortages (reduces low-priority assignments first) - Requires manual resolution for surpluses or when auto-resolution is disabled
- Returns status: NoDiscrepancy, DiscrepancyResolved, or ManualResolutionRequired
GET /api/inventoryhistory- Query inventory change history- Required:
fromandto(datetime range) - Required: at least one of
locationPathoritemId - Returns timestamped events showing amount changes, operation names, and grouping IDs
- Required:
GET /api/admin/version- Get application versionGET /api/admin/changelog- Get release historyGET /api/admin/upgrade- Check for pending database migrationsPOST /api/admin/upgrade- Apply pending database migrations
- Intro overview - What INVI is and who it’s for
- Quickstart - Minimal steps to run INVI
- Core concepts - Items, locations, assignments
- Basic use cases - Simple scenarios to get started
- Advanced docs index
- Installation Guide - Detailed setup instructions
- Configuration Guide - Environment variables and settings
- Monitoring Guide - Health checks and monitoring
- Troubleshooting - Common issues and solutions
- Business Cases - Real-world inventory management scenarios
- Understanding primaryId - Working with multiple identifier types
- Privacy Policy - Our commitment to not collecting your data
- License - Terms of use
- Setup Validation:
./validate-setup.sh- Verify your environment is configured correctly
We welcome feedback, bug reports, and feature requests. Please use GitHub Issues for all of the following:
- Report a bug — include a clear description, steps to reproduce, expected vs actual behavior, your environment (OS, Docker version, INVI version), and relevant logs.
- Request a feature — describe the problem it solves, how you envision it working, and why it’s valuable.
- General feedback — questions, suggestions, or comments.
Open an issue here: https://github.com/mak-m/invi/issues/new
Check the current version:
curl http://localhost:8080/api/admin/versionView release history:
curl http://localhost:8080/api/admin/changelog