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

# Read product specifications

> Assemble a Parent Product with every page of its included versions, BOMs, measurements, and options

Use this workflow to assemble a product specification packet or feed a product
detail view in another system. An expanded Parent Product includes related
collections in one response; each collection has its own pagination.

Before you start, set your [API key and brand](/authentication), save
[`amber-client.mjs`](/pagination#reusable-nodejs-client), and choose a
`PRODUCT_ID` with `/products?code=TEE-001`. Use Node.js 22 or later for the script.

<Steps>
  <Step title="Request the relationships you need">
    ```bash theme={null}
    curl --fail-with-body --get \
      -H "Authorization: Bearer $AMBER_API_KEY" \
      --data-urlencode "include=versions,boms,bomComponents,measurementTables,productOptions,skus" \
      --data-urlencode "includeLimit=100" \
      "https://app.amber.ai/api/public/v1/brands/$AMBER_BRAND/products/$PRODUCT_ID"
    ```

    For all supported expansions, use `include=all`. The response is a product
    object with an `included` object, not an `items` envelope around the product.
    Each entry in `included` has `items`, `totalItems`, `nextCursor`, and `url`.

    <Note>
      Use `includeLimit=100` for up to 100 rows in each relationship. The default
      is 25. The shared `productGraph()` helper below follows every continuation
      and returns completed arrays.
    </Note>
  </Step>

  <Step title="Finish every included collection">
    This script creates a local export format: `product` contains the header
    and `relationships` contains completed arrays. That format is your output,
    not a second API response shape.

    ```javascript product-specifications.mjs theme={null}
    import { productGraph } from "./amber-client.mjs";

    const productId = process.env.PRODUCT_ID;
    if (!productId) throw new Error("Set PRODUCT_ID from /products?code=TEE-001");
    console.log(JSON.stringify(await productGraph(productId), null, 2));
    ```

    ```bash theme={null}
    node product-specifications.mjs > product.json.tmp && mv product.json.tmp product.json
    ```

    Empty arrays mean no visible related rows at read time. Missing include
    names mean they were not requested. This script collects one product in
    memory; stream rows to storage instead for unusually large graphs.
  </Step>

  <Step title="Keep versions and assignments distinct">
    Use `product.currentProductVersionId`, when present, to locate the current
    row in `relationships.versions`. Do not assume the first version is current
    or the highest-numbered version is the version referenced by an order.

    | Collection | Relationship |
    | - | - |
    | `boms`, `measurementTables` | `productVersionId` selects the version |
    | `bomComponents` | `bomId` selects the BOM; `componentId` and `componentVariantId` resolve material definitions |
    | `bomSkus`, `measurementTableSkus` | Link a BOM or measurement table to individual SKUs |
    | `optionValues`, `dimensionValues`, `prices` | Link values or prices to a `productOptionId` |
    | `skuDimensionValues` | Links each SKU to its dimension values |

    Preserve version `technicalSpecs`, `packagingSpecs`, `labelingSpecs`, and
    `sizeSpecs`, along with measurement-table `sizeSpecs` and BOM
    `constructionAnnotations`, as nested JSON. Their structure can contain
    more information than a flattened spreadsheet.
  </Step>
</Steps>

## Fetch one version directly

If an order or quote supplies a `productVersionId`, use that ID to read
`/product-versions/{id}`, `/boms?productVersionId={id}`, and
`/measurement-tables?productVersionId={id}`. These reads avoid loading other
versions. Finish the BOM with `/bom-components?bomId={id}`.

## Understand the boundary of the graph

`all` means all supported **product expansions**, not every business record
that references the product. Read samples with `/samples?productId={id}`,
their rounds with `/sample-rounds?protoId={sample.id}`, and checklist results
with `/sample-checklist-results?protoRoundId={round.id}`. Quotes and orders have
their own workflows.

The `documents` expansion contains Parent Product files. Product Option,
version, SKU, Sample, and other file subjects need their own document queries.
The `images` expansion covers a wider product graph. Follow
[Download documents and images](/tutorials/download-documents) to retrieve bytes.

## Budget for repeated reads

`include=all` uses 31 expansion credits. The bucket allows two full expansions
immediately and refills at 1,000 credits per hour by default. After the initial
burst, that is roughly 32 full expansions per hour for a continuously busy key,
before accounting for other expansion requests. Honor `Retry-After` on `429`.
Continuation requests use the regular request quota and no expansion credits.

Choose a smaller `include` set for interactive reads. For a whole-brand export,
page the collections directly and join their IDs as in
[Export your catalog](/tutorials/export-catalog). See [Product graphs](/product-graphs)
for expansion semantics and [Authentication](/authentication) for limits.
