CV Jobs
CV (Computer Vision) jobs analyze observation images using trained models. Submit an observation, pick a model, and receive structured detection results.
Starting a CV job
POST
/v1/tenants/{tenantId}/cv/jobsStart a new CV analysis jobGET
/v1/tenants/{tenantId}/cv/jobs/{id}Get job status and resultsGET
/v1/tenants/{tenantId}/cv/jobsList CV jobs with paginationconst job = await tenant.cv.start({
observationId: 'obs_abc123',
model: 'shelf-detection-v2',
});
console.log(job.id); // "job_xyz789"
console.log(job.status); // "queued"Job lifecycle
| Status | Description |
|---|---|
queued | Job accepted, waiting for processing |
processing | Model is analyzing the image |
completed | Analysis finished, results available |
failed | Analysis failed (see error field) |
Polling vs webhooks
Polling
let result = await tenant.cv.get(job.id);
while (result.status === 'queued' || result.status === 'processing') {
await new Promise(r => setTimeout(r, 2000));
result = await tenant.cv.get(job.id);
}
if (result.status === 'completed') {
console.log('Detections:', result.result.detections);
} else {
console.error('Job failed:', result.error);
}Convenience helper
// Waits automatically with exponential backoff
const result = await tenant.cv.waitForCompletion(job.id, {
timeoutMs: 60000, // max wait time
});
console.log(result.result.detections);Prefer webhooks for production
Polling is fine for development, but use webhooks in production to avoid unnecessary API calls.
Result format
A completed CV job returns a result object with a detections array:
{
"id": "job_xyz789",
"status": "completed",
"model": "shelf-detection-v2",
"result": {
"detections": [
{
"objectName": "Coca-Cola 330ml",
"confidence": 0.97,
"boundingBox": { "x": 120, "y": 45, "width": 80, "height": 200 },
"attributes": {
"facings": 4,
"shelfPosition": "eye-level",
"priceTag": "2.49"
}
},
{
"objectName": "Pepsi 500ml",
"confidence": 0.92,
"boundingBox": { "x": 250, "y": 50, "width": 85, "height": 210 },
"attributes": {
"facings": 3,
"shelfPosition": "eye-level",
"priceTag": null
}
}
],
"summary": {
"totalProducts": 24,
"uniqueSKUs": 8,
"outOfStock": ["Fanta Orange 330ml"],
"complianceScore": 0.85
}
}
}
Pipeline types
The model parameter selects which CV pipeline processes the observation.
| Pipeline | Description | Requirements |
|---|---|---|
gemini | Gemini vision-only detection (no segmentation) | Gemini API key |
sam2_gemini | SAM2 segmentation + Gemini classification (default) | SAM2 service + Gemini API key |
hierarchical | Category-tree routing + SAM2 + Gemini | Categories configured in catalog |
embed_retrieve | Embedding-based similarity search + SAM2 | SKU gallery embeddings built |
combined | Hierarchical + embedding fusion (highest accuracy) | Categories + embeddings |
yolo | Custom YOLO model inference | Trained YOLO model |
yolo_gemini | YOLO detection + Gemini classification | YOLO model + Gemini API key |
Reprocessing observations
You can re-run CV analysis on existing observations with a different pipeline:
// Reprocess a single observation
const obs = await tenant.observations.reprocess('obs_abc123', {
model: 'combined',
});
// Bulk reprocess
const result = await tenant.observations.bulkReprocess({
ids: ['obs_abc123', 'obs_def456'],
model: 'sam2_gemini',
});
console.log(`Queued ${result.queued} observations`);Next steps
- Observations — Create observations to analyze
- Webhooks — Get notified when jobs complete
- Shelf Monitoring recipe — Full integration example