openapi: 3.1.0 info: title: Shelf AI Vision API version: "1.0.0" summary: Retail shelf product detection and category tagging. description: | Shelf AI Vision accepts retail shelf images and returns product-level boxes, detection confidence, category labels, class scores, and optional visual overlays. The API is designed for shelf audits, catalog cleanup, retail operations tools, and visual QA workflows. servers: - url: https://api.shelfaivision.com description: Production origin API externalDocs: description: Human-readable API docs url: https://docs.shelfaivision.com security: - ApiKeyAuth: [] - BearerAuth: [] - RapidApiProxySecret: [] tags: - name: Inference description: Product detection and category tagging endpoints. - name: Health description: Read-only service health endpoint. paths: /health/live: get: tags: [Health] summary: Check whether the receiver process is alive. operationId: getLiveHealth security: [] responses: "200": description: Receiver process is alive. headers: X-Request-ID: $ref: "#/components/headers/XRequestID" content: application/json: schema: type: object required: [status, request_id, mode] properties: status: type: string example: alive request_id: type: string example: 64b12c615db14af7ba6a8302db488aa7 mode: type: string example: receiver /v1/analyze: post: tags: [Inference] summary: Detect products and return structured category predictions. description: | Upload one JPEG, PNG, or WEBP shelf image as multipart form field `image`. The response contains one object per detected product. operationId: analyzeShelfImage requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/ImageUploadRequest" encoding: image: contentType: image/jpeg, image/png, image/webp responses: "200": description: Detection and classification result. headers: X-Request-ID: $ref: "#/components/headers/XRequestID" X-RateLimit-Limit: $ref: "#/components/headers/XRateLimitLimit" X-RateLimit-Remaining: $ref: "#/components/headers/XRateLimitRemaining" X-RateLimit-Reset: $ref: "#/components/headers/XRateLimitReset" X-RateLimit-Concurrent-Limit: $ref: "#/components/headers/XRateLimitConcurrentLimit" X-RateLimit-Concurrent-Remaining: $ref: "#/components/headers/XRateLimitConcurrentRemaining" X-RateLimit-Minute-Limit: $ref: "#/components/headers/XRateLimitMinuteLimit" X-RateLimit-Minute-Remaining: $ref: "#/components/headers/XRateLimitMinuteRemaining" X-RateLimit-Minute-Reset: $ref: "#/components/headers/XRateLimitMinuteReset" X-RateLimit-Day-Limit: $ref: "#/components/headers/XRateLimitDayLimit" X-RateLimit-Day-Remaining: $ref: "#/components/headers/XRateLimitDayRemaining" X-RateLimit-Day-Reset: $ref: "#/components/headers/XRateLimitDayReset" content: application/json: schema: $ref: "#/components/schemas/AnalyzeResponse" examples: shelfResult: $ref: "#/components/examples/AnalyzeResponseExample" "400": { $ref: "#/components/responses/APIError" } "401": { $ref: "#/components/responses/APIError" } "413": { $ref: "#/components/responses/APIError" } "415": { $ref: "#/components/responses/APIError" } "422": { $ref: "#/components/responses/APIError" } "429": { $ref: "#/components/responses/APIError" } "503": { $ref: "#/components/responses/APIError" } /v1/visualize: post: tags: [Inference] summary: Detect products and return an annotated image. description: | Runs the same model path as `/v1/analyze`, then returns an image with product boxes and labels overlaid for fast visual QA. operationId: visualizeShelfImage requestBody: required: true content: multipart/form-data: schema: $ref: "#/components/schemas/ImageUploadRequest" encoding: image: contentType: image/jpeg, image/png, image/webp responses: "200": description: Annotated image with boxes and labels. headers: X-Request-ID: $ref: "#/components/headers/XRequestID" X-Detections-Count: description: Number of detections rendered into the visualization. schema: { type: integer, example: 42 } X-RateLimit-Limit: $ref: "#/components/headers/XRateLimitLimit" X-RateLimit-Remaining: $ref: "#/components/headers/XRateLimitRemaining" X-RateLimit-Reset: $ref: "#/components/headers/XRateLimitReset" X-RateLimit-Concurrent-Limit: $ref: "#/components/headers/XRateLimitConcurrentLimit" X-RateLimit-Concurrent-Remaining: $ref: "#/components/headers/XRateLimitConcurrentRemaining" X-RateLimit-Minute-Limit: $ref: "#/components/headers/XRateLimitMinuteLimit" X-RateLimit-Minute-Remaining: $ref: "#/components/headers/XRateLimitMinuteRemaining" X-RateLimit-Minute-Reset: $ref: "#/components/headers/XRateLimitMinuteReset" X-RateLimit-Day-Limit: $ref: "#/components/headers/XRateLimitDayLimit" X-RateLimit-Day-Remaining: $ref: "#/components/headers/XRateLimitDayRemaining" X-RateLimit-Day-Reset: $ref: "#/components/headers/XRateLimitDayReset" content: image/jpeg: schema: type: string format: binary image/png: schema: type: string format: binary "400": { $ref: "#/components/responses/APIError" } "401": { $ref: "#/components/responses/APIError" } "413": { $ref: "#/components/responses/APIError" } "415": { $ref: "#/components/responses/APIError" } "422": { $ref: "#/components/responses/APIError" } "429": { $ref: "#/components/responses/APIError" } "503": { $ref: "#/components/responses/APIError" } components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key description: Direct API key header for internal testing and direct integrations. BearerAuth: type: http scheme: bearer description: "Alternative direct API key transport using `Authorization: Bearer `." RapidApiProxySecret: type: apiKey in: header name: X-RapidAPI-Proxy-Secret description: | Gateway-to-origin shared secret configured inside RapidAPI. This is not a customer-facing RapidAPI subscription key and should not be shown to end users. headers: XRequestID: description: Stable request ID for support/debugging. schema: { type: string, example: req_123 } XRateLimitLimit: description: Per-minute request limit for the current identity. schema: { type: string, example: "30" } XRateLimitRemaining: description: Remaining requests in the current minute window. schema: { type: string, example: "29" } XRateLimitReset: description: Unix timestamp when the current minute window resets. schema: { type: string, example: "1778618400" } XRateLimitConcurrentLimit: description: Concurrent request limit for the current identity. schema: { type: string, example: "2" } XRateLimitConcurrentRemaining: description: Remaining concurrent slots for the current identity. schema: { type: string, example: "1" } XRateLimitMinuteLimit: description: Per-minute request limit for the current identity. schema: { type: string, example: "30" } XRateLimitMinuteRemaining: description: Remaining requests in the current minute window. schema: { type: string, example: "29" } XRateLimitMinuteReset: description: Unix timestamp when the current minute window resets. schema: { type: string, example: "1778618400" } XRateLimitDayLimit: description: Per-day request limit for the current identity. schema: { type: string, example: "1000" } XRateLimitDayRemaining: description: Remaining requests in the current UTC day window. schema: { type: string, example: "999" } XRateLimitDayReset: description: Unix timestamp when the current UTC day window resets. schema: { type: string, example: "1778626800" } responses: APIError: description: Stable API error payload. headers: X-Request-ID: $ref: "#/components/headers/XRequestID" Retry-After: description: Present on some `429` and `503` responses. schema: { type: string, example: "1" } content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: invalidImage: $ref: "#/components/examples/InvalidImageErrorExample" unauthorized: $ref: "#/components/examples/UnauthorizedErrorExample" rateLimited: $ref: "#/components/examples/RateLimitedErrorExample" serviceBusy: $ref: "#/components/examples/ServiceBusyErrorExample" tooManyDetections: $ref: "#/components/examples/TooManyDetectionsErrorExample" schemas: ImageUploadRequest: type: object required: [image] properties: image: type: string format: binary description: | JPEG, PNG, or WEBP shelf image. Default limits: 25 MB upload size, 128x128 minimum dimensions, 8000x8000 maximum dimensions, 30 MP maximum, and 6:1 maximum aspect ratio after EXIF orientation. AnalyzeResponse: type: object required: [detections_count, detections] additionalProperties: true properties: request_id: type: string description: Request ID echoed in the `X-Request-ID` header. example: req_123 image_path: type: string description: Original client filename or safe upload label. example: shelf.jpg image_size: type: object required: [width, height] properties: width: { type: integer, example: 1600 } height: { type: integer, example: 1200 } model_versions: type: object description: Model and taxonomy versions used for this response. additionalProperties: type: string example: detector: detector_v1_yolo11l_1280 classifier: classifier_v1_multitask_v4_v3core_bs128_lr1e4 taxonomy: tag_class_taxonomy_v2 defaults: type: object description: Runtime defaults used by the service for this request. additionalProperties: true example: detection_conf: 0.25 detection_iou: 0.45 classification_batch_size: 32 classifier_bbox_padding: 0.05 max_detections: 300 detections_count: type: integer minimum: 0 example: 2 detections: type: array items: $ref: "#/components/schemas/Detection" Detection: type: object required: [bbox_xyxy, detection_score, final_classes, class_scores] additionalProperties: true properties: index: type: integer description: Detection index in the response. example: 0 detector_class_id: type: integer description: Detector class id before category classification. example: 0 detector_class_name: type: string description: Detector class name before category classification. example: product bbox_xyxy: type: array minItems: 4 maxItems: 4 description: Pixel coordinates `[x1, y1, x2, y2]` in the original image. items: { type: number } example: [120.2, 80.5, 260.1, 410.9] detection_score: type: number minimum: 0 maximum: 1 example: 0.94 final_classes: type: object description: Best class per category head. properties: product_supercategory: type: string enum: - dairy_and_eggs - meat_and_seafood - dry_grocery - bakery - snacks_and_confectionery - beverages - canned_and_condiments - frozen - baby_and_pet - household_and_hygiene - other_food - other_non_food - unknown example: beverages product_type: type: string enum: - milk - kefir - yogurt - sour_cream_smetana - cottage_cheese_tvorog - cheese - butter_margarine - dairy_dessert - eggs - sausage_deli_meat - raw_meat_poultry - fish_seafood_products - pasta - rice - grains_cereals - cereal_flakes_muesli - flour_baking_mix - sugar_salt - legumes - bread_bakery - biscuits_cookies - wafers - chocolate_candy - chips_snacks - nuts_dried_fruits - tea - coffee - cocoa_hot_chocolate - water - juice - carbonated_soft_drink - energy_drink - canned_food - sauces_condiments - spices_seasonings - oil_vinegar - jam_honey_spread - instant_meal - frozen_food - baby_food - pet_food - household_cleaning - paper_hygiene - personal_care - other_food - other_non_food - unknown example: energy_drink packaging_format: type: string enum: - bottle - carton_pack - can - jar - box - bag - pouch - cup - tub - tray - egg_carton - flow_pack - vacuum_pack - blister - wrapper - other_packaging - unknown example: can packaging_material: type: string enum: - plastic - glass - paper_cardboard - metal - foil - mixed_material - other_material - unknown example: metal storage_class: type: string enum: - refrigerated - frozen - ambient_dry - ambient_shelf_stable - other_storage - unknown example: ambient_shelf_stable additionalProperties: true class_scores: type: object description: Confidence for the selected class in each category head. additionalProperties: type: number minimum: 0 maximum: 1 example: product_supercategory: 0.98 product_type: 0.83 packaging_format: 0.91 packaging_material: 0.89 storage_class: 0.96 ErrorResponse: type: object required: [error, message, request_id] properties: error: type: string enum: - empty_upload - payload_too_large - invalid_image - unsupported_image_format - image_too_small - image_too_large - unsupported_aspect_ratio - unauthorized - public_auth_not_configured - rate_limited - model_not_ready - service_busy - inference_timeout - too_many_detections - inference_failed - visualization_failed message: type: string example: Uploaded file is not a valid image request_id: type: string example: req_123 examples: AnalyzeResponseExample: summary: Two detected shelf products value: request_id: req_123 image_path: demo-shelf-before.jpg image_size: { width: 1008, height: 490 } model_versions: detector: detector_v1_yolo11l_1280 classifier: classifier_v1_multitask_v4_v3core_bs128_lr1e4 taxonomy: tag_class_taxonomy_v2 defaults: detection_conf: 0.25 detection_iou: 0.45 classification_batch_size: 32 classifier_bbox_padding: 0.05 max_detections: 300 detections_count: 2 detections: - index: 0 detector_class_id: 0 detector_class_name: product bbox_xyxy: [184.135, 93.219, 234.845, 185.733] detection_score: 0.937166 final_classes: product_supercategory: beverages product_type: energy_drink packaging_format: can packaging_material: metal storage_class: ambient_shelf_stable class_scores: product_supercategory: 0.895886 product_type: 0.994563 packaging_format: 0.993435 packaging_material: 0.984227 storage_class: 0.971812 - index: 1 detector_class_id: 0 detector_class_name: product bbox_xyxy: [943.077, 251.138, 991.118, 315.13] detection_score: 0.930885 final_classes: product_supercategory: beverages product_type: carbonated_soft_drink packaging_format: can packaging_material: metal storage_class: ambient_shelf_stable class_scores: product_supercategory: 0.972351 product_type: 0.855162 packaging_format: 0.836693 packaging_material: 0.830492 storage_class: 0.850794 InvalidImageErrorExample: summary: Invalid image upload value: error: invalid_image message: Uploaded file is not a valid image request_id: req_123 UnauthorizedErrorExample: summary: Missing or invalid API key value: error: unauthorized message: Missing or invalid API key request_id: req_123 RateLimitedErrorExample: summary: Request limit exceeded value: error: rate_limited message: Minute request limit exceeded request_id: req_123 ServiceBusyErrorExample: summary: Workers temporarily saturated value: error: service_busy message: Receivers or workers are temporarily saturated; retry with backoff request_id: req_123 TooManyDetectionsErrorExample: summary: Detection limit exceeded value: error: too_many_detections message: Too many products were detected in the image request_id: req_123