Navin is a blockchain-powered logistics platform that improves supply chain visibility for enterprises through tokenized shipments, immutable milestone tracking, and automated settlements. By creating a zero-trust interface between logistics providers and their clients, Navin aims to ensure both parties access identical real-time data — removing information asymmetry and enabling seamless, dispute-free operations.
The backend service powers the off-chain layer of the platform, handling API logic, data aggregation, and integration with Soroban smart contracts.
- Quick Start
- Authentication
- API Response Envelope
- Pagination
- Error Handling
- Real-time Features
- Available Endpoints
- Environment Variables
- Scripts
- Contributing
Get the Navin Backend running in less than 5 minutes:
# 1. Clone the repository
git clone https://github.com/Navin-xmr/navin-backend.git
cd navin-backend
# 2. Install dependencies
npm install
# 3. Create environment file
cp .env.example .env
# 4. Update .env with your MongoDB connection string
# Edit .env and set: MONGO_URI=mongodb://...
# 5. Start the development server (with hot reload)
npm run dev
# Expected output:
# Server running on http://localhost:3000
# Connected to MongoDBThe API is now available at http://localhost:3000/api
# Check health endpoint (no auth required)
curl http://localhost:3000/api/health
# Expected response:
# { "success": true, "message": "OK", "data": { "status": "active", "uptime": 123, "timestamp": "2026-06-28T..." } }The Navin Backend uses JWT (JSON Web Tokens) for stateless authentication. All protected endpoints require a valid bearer token.
curl -X POST http://localhost:3000/api/auth/signup \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"name": "John Doe",
"password": "SecurePass123"
}'
# Response:
# {
# "success": true,
# "message": "User registered successfully",
# "data": {
# "user": {
# "_id": "507f1f77bcf86cd799439011",
# "email": "user@example.com",
# "name": "John Doe",
# "role": "VIEWER"
# },
# "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# }
# }curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePass123"
}'
# Response: { "success": true, "data": { "user": {...}, "token": "eyJhbGciOi..." } }Store the token and include it in all subsequent requests:
# Example: List shipments
curl -X GET http://localhost:3000/api/shipments \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# If token is missing or invalid, you'll receive:
# { "success": false, "message": "Missing or invalid token", "code": "ERR_AUTH_INVALID" }curl -X POST http://localhost:3000/api/auth/logout \
-H "Authorization: Bearer <your_token>"
# Response: { "success": true, "message": "Logged out successfully", "data": null }Tokens expire after 24 hours by default. When expired, the API returns:
{
"success": false,
"code": "ERR_AUTH_INVALID",
"message": "Token has expired"
}Action: Redirect user to login page and request a new token.
User roles determine which endpoints they can access:
| Role | Permission Level | Typical Use Case |
|---|---|---|
SUPER_ADMIN |
Full system access | Internal DevOps, system administration |
ADMIN |
Organization administration | Company managers, billing access |
MANAGER |
Shipment & analytics management | Logistics coordinators |
VIEWER |
Read-only access | Drivers, customers (view shipments only) |
CUSTOMER |
Minimal read access | External parties (tracking only) |
If your role lacks permissions, you'll receive:
{
"success": false,
"code": "ERR_PERMISSION_DENIED",
"message": "Insufficient permissions for this operation"
}Every successful API response follows this standard format:
{
"success": true,
"message": "Operation completed successfully",
"data": {
"_id": "507f1f77bcf86cd799439011",
"name": "Example Shipment",
"status": "IN_TRANSIT"
},
"meta": {
"page": 1,
"limit": 20,
"total": 150
}
}{
"success": false,
"message": "Human-readable error description",
"data": null,
"code": "ERR_VALIDATION_FAILED"
}success(boolean) — Whether the operation succeededmessage(string) — Human-readable descriptiondata(object|array|null) — Response payload;nullon errorscode(string) — Error code (only in error responses); see Error Codes Registrymeta(object) — Pagination metadata (only for list endpoints)
The API supports two pagination patterns: offset-based and cursor-based.
Use page and limit query parameters for offset pagination:
curl -X GET "http://localhost:3000/api/shipments?page=2&limit=20" \
-H "Authorization: Bearer <token>"
# Response includes meta:
# {
# "data": [...],
# "meta": {
# "page": 2,
# "limit": 20,
# "total": 150
# }
# }Parameters:
page(integer, default: 1) — Page number (1-indexed)limit(integer, default: 20, max: 100) — Records per page
For high-frequency data (anomalies, telemetry), use cursor-based pagination:
curl -X GET "http://localhost:3000/api/anomalies?limit=20" \
-H "Authorization: Bearer <token>"
# Response:
# {
# "data": [
# { "_id": "...", "type": "TEMPERATURE_EXCEEDED", ... },
# { "_id": "...", "type": "HUMIDITY_LOW", ... }
# ],
# "meta": {
# "nextCursor": "eyJfaWQiOiI1MDdmMWY3N2JjZjg2Y2Q3OTk0MzkwMTEifQ",
# "hasMore": true
# }
# }Fetch next page:
curl -X GET "http://localhost:3000/api/anomalies?limit=20&cursor=eyJfaWQiOiI1MDdmMWY3N2JjZjg2Y2Q3OTk0MzkwMTEifQ" \
-H "Authorization: Bearer <token>"When to use cursor-based:
- Real-time feeds (anomaly streams, telemetry)
- Data that changes frequently
- Mobile/streaming clients
All errors include a structured code field for programmatic handling. See the Error Codes Registry for the complete list.
| Status | Meaning | Example |
|---|---|---|
200 OK |
Request succeeded | GET, PATCH successful |
201 Created |
Resource created | POST successful |
400 Bad Request |
Malformed request | Missing fields, invalid types |
401 Unauthorized |
Missing/invalid token | ERR_AUTH_INVALID |
403 Forbidden |
Insufficient permissions | ERR_PERMISSION_DENIED |
404 Not Found |
Resource doesn't exist | ERR_SHIPMENT_NOT_FOUND |
409 Conflict |
Duplicate unique value | ERR_DUPLICATE_KEY (email already registered) |
500 Internal Server Error |
Unhandled exception | ERR_INTERNAL_SERVER_ERROR |
import axios from 'axios';
const api = axios.create({ baseURL: 'http://localhost:3000/api' });
api.interceptors.response.use(
response => response.data,
error => {
const code = error.response?.data?.code;
if (code === 'ERR_AUTH_INVALID') {
// Handle expired session
localStorage.removeItem('authToken');
window.location.href = '/login';
} else if (code === 'ERR_PERMISSION_DENIED') {
// Handle insufficient permissions
console.error('Access denied:', error.response.data.message);
} else if (code === 'ERR_VALIDATION_FAILED') {
// Handle validation errors
console.error('Invalid input:', error.response.data.message);
}
throw error;
}
);The backend supports WebSocket (Socket.IO) connections for real-time updates on shipments and anomalies.
import io from 'socket.io-client';
const socket = io('http://localhost:3000', {
auth: {
token: 'your_jwt_token_here'
}
});
socket.on('connect', () => {
console.log('Connected to real-time server');
});
socket.on('disconnect', () => {
console.log('Disconnected from real-time server');
});// Listen for shipment status changes
socket.on('shipment:updated', (shipment) => {
console.log('Shipment updated:', shipment);
});
// Listen for new anomalies
socket.on('anomaly:detected', (anomaly) => {
console.log('Anomaly detected:', anomaly);
});For detailed WebSocket documentation, see WebSocket Features.
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/api/health |
No | System health check (no auth required) |
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/auth/signup |
No | Register a new user |
POST |
/api/auth/login |
No | Authenticate and get JWT token |
POST |
/api/auth/logout |
Yes | Revoke current JWT |
POST |
/api/auth/api-keys |
Yes | Create machine-to-machine API key |
GET |
/api/auth/api-keys/{organizationId} |
Yes | List API keys for organization |
DELETE |
/api/auth/api-keys/{apiKeyId} |
Yes | Revoke an API key |
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/users |
Yes | ADMIN+ | List organization users |
POST |
/api/users |
Yes | ADMIN+ | Create a new user |
DELETE |
/api/users/{id} |
Yes | ADMIN+ | Delete a user (soft delete) |
POST |
/api/users/invitations |
Yes | ADMIN+ | Generate invitation link |
GET |
/api/users/invitations/verify |
No | — | Verify invitation token |
POST |
/api/users/invitations/accept |
No | — | Accept invitation & create account |
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/shipments |
Yes | VIEWER+ | List shipments (paginated) |
POST |
/api/shipments |
Yes | MANAGER+ | Create a new shipment |
GET |
/api/shipments/{id} |
Yes | VIEWER+ | Get shipment details |
PATCH |
/api/shipments/{id} |
Yes | MANAGER+ | Update shipment metadata |
PATCH |
/api/shipments/{id}/status |
Yes | MANAGER+ | Update shipment status |
POST |
/api/shipments/{id}/proof |
Yes | MANAGER+ | Upload proof of delivery |
DELETE |
/api/shipments/{id} |
Yes | ADMIN+ | Delete shipment (soft delete) |
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/telemetry |
Yes | VIEWER+ | Get telemetry records (time-series) |
GET |
/api/anomalies |
Yes | VIEWER+ | List anomalies (cursor-paginated) |
PATCH |
/api/anomalies/{id}/resolve |
Yes | MANAGER+ | Mark anomaly as resolved |
GET |
/api/analytics/performance |
Yes | VIEWER+ | Get shipment performance analytics |
| Method | Path | Auth | Role | Description |
|---|---|---|---|---|
GET |
/api/payments |
Yes | VIEWER+ | List payment records (Stellar settlements) |
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/webhooks/iot |
API Key | Receive IoT telemetry data |
POST |
/api/webhooks/stellar |
Signature | Receive Stellar settlement callbacks |
All required and optional environment variables for development and production:
| Variable | Required | Default | Description |
|---|---|---|---|
MONGO_URI |
✅ Yes | — | MongoDB connection string (e.g., mongodb://localhost:27017/navin) |
PORT |
❌ No | 3000 |
Port on which the API server listens |
NODE_ENV |
❌ No | development |
Environment mode (development, production, test) |
JWT_SECRET |
❌ No | Generated | Secret key for signing JWTs (must be strong in production) |
JWT_EXPIRY |
❌ No | 24h |
JWT expiration time (e.g., 24h, 7d) |
REDIS_URL |
❌ No | redis://localhost:6379 |
Redis connection string (for sessions, rate limiting) |
STELLAR_HORIZON_URL |
❌ No | https://horizon-testnet.stellar.org |
Stellar Horizon API endpoint |
STELLAR_NETWORK_PASSPHRASE |
❌ No | Test SDF Network ; September 2015 |
Stellar network identifier |
LOG_LEVEL |
❌ No | info |
Logging level (debug, info, warn, error) |
CORS_ORIGINS |
❌ No | http://localhost:3000,http://localhost:5173 |
Comma-separated list of allowed origins |
API_KEY_PREFIX |
❌ No | sk_ |
Prefix for generated API keys |
# Database
MONGO_URI=mongodb://user:password@mongodb.example.com:27017/navin
# Server
PORT=3000
NODE_ENV=production
# Authentication
JWT_SECRET=your-super-secret-key-change-this-in-production
JWT_EXPIRY=24h
# Redis (for sessions & caching)
REDIS_URL=redis://:password@redis.example.com:6379
# Stellar Blockchain
STELLAR_HORIZON_URL=https://horizon.stellar.org
STELLAR_NETWORK_PASSPHRASE=Public Global Stellar Network ; September 2015
# Logging
LOG_LEVEL=info
# CORS
CORS_ORIGINS=https://app.navin.io,https://staging.navin.io
# API Keys
API_KEY_PREFIX=sk_| Command | Purpose |
|---|---|
npm run dev |
Start development server with hot reload (tsx watch) |
npm run build |
Compile TypeScript to JavaScript in dist/ |
npm run start |
Run production build |
npm run typecheck |
Run TypeScript type checker |
npm run lint |
Run ESLint and Prettier checks |
npm run lint:fix |
Fix linting and formatting issues |
npm test |
Run test suite (Jest) |
npm test -- --watch |
Run tests in watch mode |
npm run migrations:up |
Run pending database migrations |
npm run migrations:down |
Rollback last migration |
We welcome contributions! Please see CONTRIBUTING.md for guidelines on branching, commits, pull requests, and our build/test requirements.
If you discover a security vulnerability, email navinxmr@gmail.com — do not open a public issue.
Built with leveraging the Stellar ecosystem technology