> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shelfforce.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Batch Analysis

> Submit multiple shelf images for analysis in a single API call.

When you need to analyze multiple shelf photos — for example, every aisle in a store or photos from a field team's daily route — use the batch endpoint to submit up to 20 images in a single request.

## When to use batch

* Processing a set of photos from a single store visit
* Analyzing images uploaded by field teams throughout the day
* Running periodic audits across multiple locations
* Any workflow where you have multiple images ready to submit at once

## Submitting a batch

Send a `POST` request to the batch analyses endpoint with an array of images:

```bash theme={null}
curl -X POST https://shelfforce.ai/api/v1/analyses/batch \
  -H "Authorization: Bearer sf_live_a1b2c3d4..." \
  -H "Content-Type: application/json" \
  -d '{
    "images": [
      {
        "imageUrl": "https://example.com/store-42/aisle-1.jpg",
        "metadata": { "store": "store-42", "aisle": "1" }
      },
      {
        "imageUrl": "https://example.com/store-42/aisle-2.jpg",
        "metadata": { "store": "store-42", "aisle": "2" }
      },
      {
        "imageUrl": "https://example.com/store-42/aisle-3.jpg",
        "metadata": { "store": "store-42", "aisle": "3" }
      }
    ]
  }'
```

### Request parameters

| Parameter             | Type     | Required | Description                                                                                                                             |
| --------------------- | -------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `images`              | `array`  | Yes      | Array of image objects. Max size depends on your plan tier (see [Limits](#limits)).                                                     |
| `images[].imageUrl`   | `string` | Yes      | Publicly accessible URL of the shelf image.                                                                                             |
| `images[].externalId` | `string` | No       | Your own reference ID for this image (e.g., customer ID, campaign ID).                                                                  |
| `images[].metadata`   | `object` | No       | Arbitrary key-value pairs (max 10 keys, string values, 500 chars each).                                                                 |
| `images[].placeId`    | `string` | No       | Shelfforce place ID to associate with this image.                                                                                       |
| `images[].taskId`     | `string` | No       | Shelfforce task ID to associate with this image.                                                                                        |
| `callbackUrl`         | `string` | No       | HTTPS URL to receive a POST for each completed/failed analysis. A `callbackSecret` is returned per analysis for signature verification. |

### Response

```json theme={null}
{
  "batchId": "batch_1a2b3c4d",
  "analyses": [
    {
      "id": "an_001",
      "status": "processing",
      "imageUrl": "https://example.com/store-42/aisle-1.jpg",
      "metadata": { "store": "store-42", "aisle": "1" }
    },
    {
      "id": "an_002",
      "status": "processing",
      "imageUrl": "https://example.com/store-42/aisle-2.jpg",
      "metadata": { "store": "store-42", "aisle": "2" }
    },
    {
      "id": "an_003",
      "status": "processing",
      "imageUrl": "https://example.com/store-42/aisle-3.jpg",
      "metadata": { "store": "store-42", "aisle": "3" }
    }
  ],
  "creditsConsumed": 3,
  "createdAt": "2026-02-23T10:30:00Z"
}
```

Each image in the batch creates a separate analysis with its own ID. The analyses run in parallel.

## Credit handling

Batch analysis uses an **all-or-nothing** credit check:

* Each image costs 1 credit (same as a single analysis).
* Before processing begins, Shelfforce verifies you have enough credits for the entire batch.
* If you do not have enough credits, the entire request is rejected — no images are analyzed and no credits are consumed.

```json theme={null}
// Submitting 10 images with only 5 credits remaining:
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "message": "Insufficient credits. This batch requires 10 credits but you have 5 remaining.",
    "details": {
      "required": 10,
      "available": 5
    }
  }
}
```

## Retrieving results

Each analysis in the batch has its own ID. Poll individual analyses for results:

```bash theme={null}
curl https://shelfforce.ai/api/v1/analyses/an_001 \
  -H "Authorization: Bearer sf_live_a1b2c3d4..."
```

Or use webhooks to be notified as each analysis completes. If you provided a `callbackUrl` in the batch request, you will receive a separate webhook for each image as it finishes.

### Checking batch status

You can also query the batch endpoint to see the status of all analyses in the batch:

```bash theme={null}
curl https://shelfforce.ai/api/v1/analyses/batch/batch_1a2b3c4d \
  -H "Authorization: Bearer sf_live_a1b2c3d4..."
```

```json theme={null}
{
  "batchId": "batch_1a2b3c4d",
  "status": "partial",
  "total": 3,
  "completed": 2,
  "processing": 1,
  "failed": 0,
  "analyses": [
    { "id": "an_001", "status": "completed" },
    { "id": "an_002", "status": "completed" },
    { "id": "an_003", "status": "processing" }
  ]
}
```

The batch `status` is one of:

* `processing` — All analyses are still running.
* `partial` — Some analyses have completed, others are still running.
* `completed` — All analyses have finished (either completed or failed).

## Idempotency keys

Use idempotency keys to safely retry batch requests without creating duplicate analyses. If a request with the same idempotency key is submitted again, Shelfforce returns the existing analysis instead of creating a new one.

```json theme={null}
{
  "images": [
    {
      "imageUrl": "https://example.com/shelf.jpg",
      "idempotencyKey": "store-42-aisle-1-2026-02-23"
    }
  ]
}
```

<Note>
  Idempotency keys are scoped to your organisation and expire after 24 hours. Use a combination of store, location, and date to create meaningful keys.
</Note>

## Best practices

<CardGroup cols={2}>
  <Card title="Group by store visit" icon="store">
    Submit all photos from a single store visit in one batch. This makes it easy to correlate results and reduces API calls.
  </Card>

  <Card title="Use metadata" icon="tag">
    Attach store IDs, aisle numbers, and dates as metadata so you can filter and group results later.
  </Card>

  <Card title="Use idempotency keys" icon="shield-check">
    Always include idempotency keys, especially when retrying failed requests or when your pipeline might submit the same image twice.
  </Card>

  <Card title="Combine with webhooks" icon="bell">
    Set a `callbackUrl` on the batch or register a persistent webhook for `analysis.completed` to avoid polling each analysis individually.
  </Card>
</CardGroup>

## Limits

The maximum number of images per batch depends on your plan tier:

| Plan    | Max images per batch |
| ------- | -------------------- |
| Free    | 20                   |
| Starter | 20                   |
| Growth  | 50                   |
| Pro     | 100                  |
| Scale   | 200                  |

You can check your current batch limit programmatically via `GET /api/v1/usage` — the response includes a `maxBatchSize` field.

| Constraint              | Value           |
| ----------------------- | --------------- |
| Maximum image file size | 20 MB           |
| Supported formats       | JPEG, PNG, WebP |

<Tip>
  If you need to process more images than your tier allows, split them into multiple batch requests. Use idempotency keys to prevent duplicates if you are retrying.
</Tip>
