6de2455917
- Added GLOBAL_MARKETS_TITLE to all translation files - Updated footer with 12 markets (4 active + 8 upcoming) - Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi - Built and deployed to production - CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
367 lines
6.1 KiB
Markdown
367 lines
6.1 KiB
Markdown
# VIMS API Documentation
|
|
|
|
## Base URL
|
|
```
|
|
Production: https://vims.landvex.com/api/v1
|
|
Development: http://localhost:3450/api/v1
|
|
```
|
|
|
|
## Authentication
|
|
All endpoints require Bearer token authentication:
|
|
```
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
## Endpoints
|
|
|
|
### Objects
|
|
|
|
#### List Objects
|
|
```http
|
|
GET /api/v1/objects
|
|
```
|
|
|
|
Query Parameters:
|
|
- `type` - Filter by object type (atm, charging_station, parking_meter, defibrillator)
|
|
- `status` - Filter by status (green, yellow, orange, red, unknown)
|
|
- `customerId` - Filter by customer
|
|
- `page` - Page number (default: 1)
|
|
- `limit` - Items per page (default: 20)
|
|
- `search` - Search in name, externalId, address
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"objects": [
|
|
{
|
|
"id": "uuid",
|
|
"name": "ATM Sveavägen 123",
|
|
"objectType": {
|
|
"name": "Bankomat",
|
|
"category": "payment"
|
|
},
|
|
"currentStatus": "green",
|
|
"location": {
|
|
"latitude": 59.3368,
|
|
"longitude": 18.0555
|
|
},
|
|
"lastInspection": "2026-07-08T10:00:00Z"
|
|
}
|
|
],
|
|
"pagination": {
|
|
"page": 1,
|
|
"limit": 20,
|
|
"total": 100,
|
|
"pages": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Object
|
|
```http
|
|
POST /api/v1/objects
|
|
```
|
|
|
|
Request Body:
|
|
```json
|
|
{
|
|
"objectTypeId": "uuid",
|
|
"customerId": "uuid",
|
|
"name": "ATM Sveavägen 123",
|
|
"externalId": "ATM-001",
|
|
"location": {
|
|
"latitude": 59.3368,
|
|
"longitude": 18.0555
|
|
},
|
|
"address": "Sveavägen 123, Stockholm",
|
|
"manufacturer": "NCR",
|
|
"model": "SelfServ 22",
|
|
"installationDate": "2025-01-15"
|
|
}
|
|
```
|
|
|
|
#### Set Baseline Images
|
|
```http
|
|
POST /api/v1/objects/:id/baseline
|
|
```
|
|
|
|
Request Body:
|
|
```json
|
|
{
|
|
"images": [
|
|
{
|
|
"angle": "front",
|
|
"imageUrl": "https://s3.landvex.com/baseline/atm-001-front.jpg"
|
|
},
|
|
{
|
|
"angle": "back",
|
|
"imageUrl": "https://s3.landvex.com/baseline/atm-001-back.jpg"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Observations
|
|
|
|
#### Upload Observation
|
|
```http
|
|
POST /api/v1/observations
|
|
```
|
|
|
|
Content-Type: `multipart/form-data`
|
|
|
|
Fields:
|
|
- `images` - Image files (JPEG, PNG, WebP)
|
|
- `objectId` - Object UUID
|
|
- `angle` - Camera angle (front, back, left, right, top, detail)
|
|
- `zoomerId` - Zoomer UUID (optional)
|
|
- `missionId` - Mission UUID (optional)
|
|
- `takenAt` - ISO timestamp (optional)
|
|
- `gpsAccuracy` - GPS accuracy in meters (optional)
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"observations": [
|
|
{
|
|
"id": "uuid",
|
|
"status": "pending",
|
|
"imageUrl": "https://s3.landvex.com/obs/..."
|
|
}
|
|
],
|
|
"objectId": "uuid",
|
|
"processed": 1
|
|
}
|
|
```
|
|
|
|
#### Get Observation
|
|
```http
|
|
GET /api/v1/observations/:id
|
|
```
|
|
|
|
Response includes detections:
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"imageUrl": "...",
|
|
"angle": "front",
|
|
"status": "analyzed",
|
|
"detections": [
|
|
{
|
|
"componentType": "card_reader",
|
|
"confidence": 0.95,
|
|
"boundingBox": {
|
|
"x": 0.1,
|
|
"y": 0.2,
|
|
"width": 0.3,
|
|
"height": 0.1
|
|
},
|
|
"isAnomaly": false
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Compare with Baseline
|
|
```http
|
|
GET /api/v1/observations/:id/compare
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"observationId": "uuid",
|
|
"isSignificant": true,
|
|
"changeType": "structural",
|
|
"metrics": {
|
|
"pixelDifference": 0.15,
|
|
"structuralDifference": 0.25,
|
|
"overallDifference": 0.20
|
|
},
|
|
"confidence": 0.92,
|
|
"diffVisualization": "base64encoded..."
|
|
}
|
|
```
|
|
|
|
### Detections
|
|
|
|
#### List Detections
|
|
```http
|
|
GET /api/v1/detections
|
|
```
|
|
|
|
Query Parameters:
|
|
- `objectId` - Filter by object
|
|
- `componentType` - Filter by component (card_reader, pin_pad, etc.)
|
|
- `isAnomaly` - Filter anomalies (true/false)
|
|
- `severity` - Filter by severity (low, medium, high, critical)
|
|
|
|
#### Verify Detection
|
|
```http
|
|
POST /api/v1/detections/:id/verify
|
|
```
|
|
|
|
Request Body:
|
|
```json
|
|
{
|
|
"isCorrect": true,
|
|
"correctedType": "card_reader",
|
|
"notes": "Verified by security team"
|
|
}
|
|
```
|
|
|
|
### Alerts
|
|
|
|
#### List Alerts
|
|
```http
|
|
GET /api/v1/alerts
|
|
```
|
|
|
|
Query Parameters:
|
|
- `status` - open, acknowledged, investigating, resolved, false_positive
|
|
- `riskLevel` - green, yellow, orange, red
|
|
- `objectId` - Filter by object
|
|
|
|
#### Update Alert Status
|
|
```http
|
|
PUT /api/v1/alerts/:id/status
|
|
```
|
|
|
|
Request Body:
|
|
```json
|
|
{
|
|
"status": "resolved",
|
|
"resolution": "False positive - approved maintenance",
|
|
"assignedTo": "user-uuid"
|
|
}
|
|
```
|
|
|
|
#### Escalate Alert
|
|
```http
|
|
POST /api/v1/alerts/:id/escalate
|
|
```
|
|
|
|
Request Body:
|
|
```json
|
|
{
|
|
"reason": "Potential skimmer device detected",
|
|
"escalateTo": "security-team"
|
|
}
|
|
```
|
|
|
|
### Dashboard
|
|
|
|
#### Overview Statistics
|
|
```http
|
|
GET /api/v1/dashboard/overview
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"summary": {
|
|
"totalObjects": 150,
|
|
"activeAlerts": 12,
|
|
"recentObservations": 45,
|
|
"overdueObjects": 3,
|
|
"compliance": "98.0"
|
|
},
|
|
"objectStats": {
|
|
"green": 130,
|
|
"yellow": 10,
|
|
"orange": 5,
|
|
"red": 2
|
|
},
|
|
"alertRiskStats": {
|
|
"orange": 8,
|
|
"red": 4
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Map Objects
|
|
```http
|
|
GET /api/v1/dashboard/objects
|
|
```
|
|
|
|
Query Parameters:
|
|
- `bounds` - Geo bounds: `{"sw":{"lat":59.3,"lng":18.0},"ne":{"lat":59.4,"lng":18.1}}`
|
|
- `status` - Filter by status
|
|
|
|
#### Activity Timeline
|
|
```http
|
|
GET /api/v1/dashboard/timeline?days=7
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"observations": [
|
|
{"date": "2026-07-01", "count": 15},
|
|
{"date": "2026-07-02", "count": 20}
|
|
],
|
|
"alerts": [
|
|
{"date": "2026-07-01", "riskLevel": "orange", "count": 2}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Top Priority Alerts
|
|
```http
|
|
GET /api/v1/dashboard/top-alerts
|
|
```
|
|
|
|
## Webhooks
|
|
|
|
VIMS can send webhooks to your endpoint:
|
|
|
|
### Alert Webhook
|
|
```json
|
|
{
|
|
"event": "vims.alert",
|
|
"timestamp": "2026-07-08T12:00:00Z",
|
|
"data": {
|
|
"alertId": "uuid",
|
|
"riskLevel": "red",
|
|
"title": "Skimmer detected",
|
|
"message": "Potential skimmer device found on ATM",
|
|
"objectId": "uuid",
|
|
"customerId": "uuid"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Observation Webhook
|
|
```json
|
|
{
|
|
"event": "vims.observation",
|
|
"timestamp": "2026-07-08T12:00:00Z",
|
|
"data": {
|
|
"observationId": "uuid",
|
|
"objectId": "uuid",
|
|
"status": "analyzed",
|
|
"riskLevel": "green"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Responses
|
|
|
|
```json
|
|
{
|
|
"error": "Validation Error",
|
|
"message": "Missing required fields",
|
|
"fields": ["objectId", "angle"]
|
|
}
|
|
```
|
|
|
|
Status Codes:
|
|
- `200` - Success
|
|
- `201` - Created
|
|
- `400` - Bad Request
|
|
- `401` - Unauthorized
|
|
- `403` - Forbidden
|
|
- `404` - Not Found
|
|
- `409` - Conflict
|
|
- `500` - Internal Server Error
|