---
title: "Stock variance measured from posted counts, attributed to each variant's default supplier"
method: GET
path: "/api/v1/stocktakes/variance/by-supplier"
tags: ["stocktakes"]
---

# Stock variance measured from posted counts, attributed to each variant's default supplier

`GET /api/v1/stocktakes/variance/by-supplier`

## Request

- Base URL: `https://api.app.tightly.io`
- URL: `https://api.app.tightly.io/api/v1/stocktakes/variance/by-supplier`
- Auth: HTTP bearer

Reads `system_quantity` against `counted_quantity` on POSTED counts only, and puts each counted line to the variant's default supplier. Open counts are never read: an unfinished count is not a measurement.

Losses and gains are served separately and never netted, so there is no net field to reach for. A location that loses 500 and finds 480 has a counting problem, not a variance of 20. Nothing here is a shrink figure either, counting short can be theft, damage, a mis-shipment, a receiving error or a miscount, and counting long is found stock.

Every counted line lands in exactly one `buckets` entry, `default_supplier`, `no_default_supplier` or `no_supplier_on_file`, so the buckets sum to `totals` on every unit and line figure. The two unattributed buckets carry `attribution_reason` instead of a supplier and are never folded into one. On an attributed bucket, `multi_supplier_line_count` says how many of its lines came from variants carrying more than one supplier.

`loss_cost` and `gain_cost` are null, never 0, where there is nothing priceable, and `cost_reason` says why; `*_units_unpriced` says how many units the money leaves out even when it is populated. `currency` is null unless one denomination covers the lot.

A supplier with no posted count is not a supplier with clean stock: it is counted in `measurement.suppliers_with_no_reading` rather than served as a zero row. For the lines behind one count, use get_stocktake_lines_table.

Scope: `stocktakes:read`.

## Query parameters

- `counted_from` string, date
- `counted_to` string, date
- `location_id` string

## Headers

- `Tightly-Version` string

## Response `200`

What was measured, the totals over every counted line, and one bucket per attribution. The buckets sum to the totals.

- object
  - `data` GetVarianceBySupplierPayload
    - `buckets` StockVarianceBucket[]
      - `attribution` 'default_supplier' | 'no_default_supplier' | 'no_supplier_on_file', required
      - `attribution_reason` string, nullable
      - `figures` StockVarianceFigures, required
        - `cost_reason` string, nullable
        - `counted_line_count` integer, required
        - `currency` string, nullable
        - `currency_reason` string, nullable
        - `gain_cost` number, nullable
        - `gain_line_count` integer, required
        - `gain_units` integer, required
        - `gain_units_unpriced` integer, required
        - `loss_cost` number, nullable
        - `loss_line_count` integer, required
        - `loss_units` integer, required
        - `loss_units_unpriced` integer, required
        - `matched_line_count` integer, required
        - `variant_count` integer, required
      - `multi_supplier_line_count` integer
      - `supplier_id` string, nullable
      - `supplier_name` string, nullable
    - `measurement` StockVarianceMeasurement, required
      - `counted_line_count` integer, required
      - `first_counted_on` string, nullable
      - `last_counted_on` string, nullable
      - `no_measurement_reason` string, nullable
      - `open_stocktake_count` integer, required
      - `posted_stocktake_count` integer, required
      - `suppliers_measured` integer, required
      - `suppliers_on_file` integer, required
      - `suppliers_with_no_reading` integer, required
      - `uncounted_line_count` integer, required
      - `variants_measured` integer, required
      - `variants_on_file` integer, required
      - `variants_with_no_reading` integer, required
      - `window_from` string, nullable
      - `window_source` string, nullable
      - `window_to` string, nullable
    - `totals` StockVarianceFigures, required
      - `cost_reason` string, nullable
      - `counted_line_count` integer, required
      - `currency` string, nullable
      - `currency_reason` string, nullable
      - `gain_cost` number, nullable
      - `gain_line_count` integer, required
      - `gain_units` integer, required
      - `gain_units_unpriced` integer, required
      - `loss_cost` number, nullable
      - `loss_line_count` integer, required
      - `loss_units` integer, required
      - `loss_units_unpriced` integer, required
      - `matched_line_count` integer, required
      - `variant_count` integer, required
  - `message` object: severity, service and desc.

## Other responses

- `400`: A date could not be read, or `counted_from` is after `counted_to`.
- `401`: No usable key: malformed, unknown, revoked, expired or stopped. One refusal covers all five, telling a caller which is which maps the surface for them. A request with no Authorization header at all is refused 400 before any key is looked for.
- `403`: The key may not reach this operation. `scope_missing` when the key does not hold Stocktakes; `organization_mismatch` when the path names an organisation that is not the key's; `ip_not_allowed` when the caller's address is outside the key's allowlist.
- `429`: The key has spent its allowance for this minute. 600 reads and 120 writes a minute, counted per key, refused calls included. `Retry-After` says how long to wait.
- `503`: The database is briefly out of reach, which is what a failover or a full connection pool looks like from outside. Wait the seconds `Retry-After` names and send the request again. A read is safe to repeat. A write is not, because the connection was lost in the middle of it, so read the object back before sending it a second time. Branch on the status rather than on `code`, which is `POSTGRES_UNAVAILABLE` from one of the two seams that raise this and `SERVICE_UNAVAILABLE` from the other.

---

[API](https://skmtc.dev/tightly/apis/tightly-api.md) · [All operations](https://skmtc.dev/tightly/apis/tightly-api/llms.txt) · [OpenAPI document](https://skmtc.dev/tightly/apis/tightly-api/revisions/199f7eb35afb?raw)
