> ## 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.

# Quickstart

> Analyze your first shelf in 60 seconds.

This guide walks you through submitting a shelf photo, waiting for results, and reading the structured product data.

<Tip>
  **Prefer the CLI?** Install it with `npm install -g @shelfforce/cli`, run `sf login`, then `sf run <image>`. See the [CLI guide](/guides/cli) for details.
</Tip>

## Prerequisites

* A Shelfforce account ([sign up here](https://shelfforce.ai))
* An API key with `write` permissions

## How the analysis flow works

Shelf analysis is **asynchronous**. When you submit an image, Shelfforce queues it for processing and immediately returns an analysis ID. You then retrieve the results once processing completes.

```
1. POST /analyses        →  You get back an analysis ID (status: "processing")
2. Analysis runs         →  Shelfforce's vision pipeline processes the image (10-30 seconds)
3. GET /analyses/:id     →  You retrieve the completed results with all detected products
```

There are two ways to know when results are ready:

| Method       | Best for               | How it works                                                             |
| ------------ | ---------------------- | ------------------------------------------------------------------------ |
| **Polling**  | Quick testing, scripts | Loop `GET /analyses/:id` every 3-5 seconds until `status` is `completed` |
| **Webhooks** | Production systems     | Register a URL and Shelfforce POSTs the result to you when ready         |

This quickstart uses polling. For webhooks, see the [Webhooks guide](/webhooks).

<Steps>
  <Step title="Get your API key">
    Navigate to [Settings > API Keys](https://shelfforce.ai/home/developers) in the Shelfforce dashboard. Click **Create API Key**, give it a name, and select the `write` role.

    Copy the key immediately — it is only shown once.

    Your key will look like this:

    ```
    sf_live_a1b2c3d4e5f6...
    ```

    <Warning>
      Store your API key securely. Never commit it to source control or expose it in client-side code.
    </Warning>
  </Step>

  <Step title="Submit an image for analysis">
    Send a `POST` request to the analyses endpoint with the URL of a shelf image. The response comes back immediately with `status: "processing"` — the analysis runs in the background.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST https://shelfforce.ai/api/v1/analyses \
        -H "Authorization: Bearer sf_live_a1b2c3d4..." \
        -H "Content-Type: application/json" \
        -d '{
          "imageUrl": "https://example.com/shelf.jpg"
        }'
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://shelfforce.ai/api/v1/analyses",
          headers={
              "Authorization": "Bearer sf_live_a1b2c3d4...",
              "Content-Type": "application/json",
          },
          json={
              "imageUrl": "https://example.com/shelf.jpg",
          },
      )

      analysis = response.json()["data"]
      print(analysis["id"])  # "an_g7h8j9k0"
      ```

      ```typescript Node.js theme={null}
      const response = await fetch("https://shelfforce.ai/api/v1/analyses", {
        method: "POST",
        headers: {
          "Authorization": "Bearer sf_live_a1b2c3d4...",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          imageUrl: "https://example.com/shelf.jpg",
        }),
      });

      const { data: analysis } = await response.json();
      console.log(analysis.id); // "an_g7h8j9k0"
      ```
    </CodeGroup>

    The response includes an analysis ID and an initial status of `processing`:

    ```json theme={null}
    {
      "data": {
        "id": "an_g7h8j9k0",
        "status": "processing",
        "createdAt": "2026-02-23T10:30:00Z"
      }
    }
    ```

    <Note>
      One credit is consumed per analysis. See [Credits](/credits) for details.
    </Note>
  </Step>

  <Step title="Poll for results">
    Analysis typically completes in **10-30 seconds** depending on image complexity. Poll the analysis endpoint until the status changes to `completed`:

    <CodeGroup>
      ```bash curl theme={null}
      # Poll every 3 seconds until completed
      while true; do
        RESULT=$(curl -s https://shelfforce.ai/api/v1/analyses/an_g7h8j9k0 \
          -H "Authorization: Bearer sf_live_a1b2c3d4...")

        STATUS=$(echo "$RESULT" | jq -r '.data.status')
        echo "Status: $STATUS"

        if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
          echo "$RESULT" | jq .
          break
        fi

        sleep 3
      done
      ```

      ```python Python theme={null}
      import time
      import requests

      analysis_id = "an_g7h8j9k0"

      while True:
          response = requests.get(
              f"https://shelfforce.ai/api/v1/analyses/{analysis_id}",
              headers={"Authorization": "Bearer sf_live_a1b2c3d4..."},
          )

          result = response.json()["data"]
          print(f"Status: {result['status']}")

          if result["status"] in ("completed", "failed"):
              break

          time.sleep(3)

      # result now contains the full analysis with products
      print(f"Found {result['productCount']} products")
      ```

      ```typescript Node.js theme={null}
      const analysisId = "an_g7h8j9k0";

      let result;
      while (true) {
        const response = await fetch(
          `https://shelfforce.ai/api/v1/analyses/${analysisId}`,
          {
            headers: { "Authorization": "Bearer sf_live_a1b2c3d4..." },
          }
        );

        const { data } = await response.json();
        console.log(`Status: ${data.status}`);

        if (data.status === "completed" || data.status === "failed") {
          result = data;
          break;
        }

        await new Promise((resolve) => setTimeout(resolve, 3000));
      }

      // result now contains the full analysis with products
      console.log(`Found ${result.productCount} products`);
      ```
    </CodeGroup>

    <Tip>
      For production use, set up [webhooks](/webhooks) to receive a notification when analysis completes instead of polling. Webhooks are more efficient and eliminate wasted requests.
    </Tip>
  </Step>

  <Step title="View detected products">
    Once the status is `completed`, the response includes a `products` array with every detected item:

    ```json theme={null}
    {
      "data": {
        "id": "an_g7h8j9k0",
        "status": "completed",
        "totalRuns": 1,
        "completedRuns": 1,
        "failedRuns": 0,
        "productCount": 12,
        "createdAt": "2026-02-23T10:30:00Z",
        "completedAt": "2026-02-23T10:30:18Z",
        "products": [
          {
            "id": "prd_k1l2m3",
            "brand": "Coca-Cola",
            "description": "Coca-Cola Original 330ml Can",
            "category": "Beverages",
            "subcategory": "Carbonated Soft Drinks",
            "units": 4,
            "price": 1.49,
            "currency": "USD",
            "onSale": false,
            "confidence": 0.95,
            "shelfPosition": "eye-level",
            "fixtureType": "shelf"
          },
          {
            "id": "prd_n4o5p6",
            "brand": "Pepsi",
            "description": "Pepsi Original 330ml Can",
            "category": "Beverages",
            "subcategory": "Carbonated Soft Drinks",
            "units": 3,
            "price": 1.29,
            "discountedPrice": 1.19,
            "currency": "USD",
            "onSale": true,
            "confidence": 0.92,
            "shelfPosition": "eye-level",
            "fixtureType": "shelf"
          }
        ]
      }
    }
    ```

    Each product includes:

    | Field                       | Description                                                     |
    | --------------------------- | --------------------------------------------------------------- |
    | `brand`                     | Detected brand name                                             |
    | `description`               | Full product description as seen on shelf                       |
    | `units`                     | Number of visible facings                                       |
    | `price` / `discountedPrice` | Detected shelf price and sale price (if applicable)             |
    | `currency`                  | ISO 4217 currency code                                          |
    | `onSale`                    | Whether the product appears to be on promotion                  |
    | `confidence`                | Detection confidence score (0.0 to 1.0)                         |
    | `shelfPosition`             | Vertical position: `top`, `eye-level`, `middle`, `bottom`       |
    | `fixtureType`               | Where it was found: `shelf`, `fridge`, `floor-display`, `other` |
  </Step>

  <Step title="Next steps">
    You have successfully analyzed your first shelf image. Here is where to go next:

    <CardGroup cols={2}>
      <Card title="Shelf Analysis Guide" icon="search" href="/guides/shelf-analysis">
        Deep dive into the analysis pipeline and all available fields.
      </Card>

      <Card title="Batch Analysis" icon="gallery-horizontal-end" href="/guides/batch-analysis">
        Process up to 20 images in a single request.
      </Card>

      <Card title="Webhooks" icon="bell" href="/webhooks">
        Get notified when analyses complete instead of polling.
      </Card>

      <Card title="Field Operations" icon="clipboard-list" href="/guides/field-operations">
        Create tasks and manage stores for field team workflows.
      </Card>
    </CardGroup>
  </Step>
</Steps>
