---
title: "Compare two items side-by-side"
method: GET
path: "/items/{id1}/compare/{id2}"
tags: ["items"]
---

# Compare two items side-by-side

`GET /items/{id1}/compare/{id2}`

Returns a detailed comparison of two items including specifications, similarity scores, and spec differences for side-by-side display

## Path parameters

- `id1` string, uuid, required
- `id2` string, uuid, required

## Response `200`

OK

- ModelsItemComparisonResponse
  - `class_comparison` ModelsPairClassComparison
    - `breakdown` ModelsPairClassFactor[] — Breakdown lists the factors THIS class judges by (decisive first) — different per category, replacing the legacy composite breakdown.
      - `label` string
      - `score` number
    - `class` string
    - `reason` string — Reason is the class-specific explanation generated from the same evidence as the verdict — it can never contradict the class chip.
    - `rows` ModelsPairClassComparisonRow[]
      - `group` string — Dimensions | Attributes | Specifications | Relationship
      - `key` string
      - `status` string — match (identity-grade) | close (variant band) | diff | only_a | only_b | info
      - `value_a` string
      - `value_b` string
    - `score` number — Score is the rule-derived similarity in [0,1]: the class fixes the band (a product variant can never score like a duplicate) and the evidence rows position the pair within it. Replaces the embedding/composite percentage on the compare page for classified tenants.
  - `classification` string — "exact_duplicate", "duplicate", "alternative", "different"
  - `close_specs` integer
  - `confidence` number
  - `different_specs` integer
  - `item1` ModelsItemComparisonSide
    - `category` string
    - `created_at` string
    - `id` string
    - `internal_code` string — drawing internal code (Kacher-test); small identifier line
    - `is_preferred` boolean
    - `manufacturer` string
    - `part_number` string
    - `references` string[]
    - `source_documents` ModelsSourceDocumentInfo[]
      - `classification` string — Document classification (e.g. datasheet, technical_drawing)
      - `filename` string — Display filename (path prefix stripped)
      - `id` string — Document ID
      - `mesh_url` string — Signed URL for the GLB 3D preview mesh
      - `mime_type` string — MIME type (e.g. application/pdf, model/jt)
      - `status` string — Document processing status
      - `tables` ModelsDocumentTable[] — Extracted content from document
        - `headers` string[] — Table column headers
        - `id` string — Table UUID
        - `page_number` integer — Page number where table was found
        - `rows` array[] — Table data rows
          - string[]
        - `table_index` integer — Index of table on the page (0-based)
      - `url` string — Signed URL for document access
    - `specifications` ModelsMatchedSpec[]
      - `canonical_name` string — Canonical attribute name (e.g., "input_voltage_max")
      - `canonical_unit` string — Catalog's expected unit (distinct from ucum_unit)
      - `confidence` number — Match confidence (0-1)
      - `count` string — Number of like features (e.g., "4" identical holes); model-extract part-analysis
      - `extracted_at` string — ISO 8601 timestamp when this spec was extracted
      - `match_method` string — How spec was matched to canonical name
      - `normalized_value` unknown
      - `original_key` string — Attribute name in English (translated from raw_key if non-English)
      - `original_unit` string — Original unit from document
      - `original_value` string — Value in English (translated from raw_value if non-English)
      - `page_number` integer — Page number in source document
      - `provisional_canonical` boolean — True when matched candidate has no confirmed canonical_name yet
      - `qualifier` string — Qualifier: min, max, typ, nominal
      - `qualifiers` string[] — Additional qualifiers (e.g., AC, DC)
      - `raw_key` string — Attribute name exactly as written in the document
      - `raw_value` string — Value exactly as written in the document
      - `registry_key_id` string — SHA-1 key_id from spec_key_registry
      - `rejected_match` string — LLM's suggestion when confidence was too low
      - `similarity_relevant` boolean — Model's per-spec flag for which features drive part matching (model-extract)
      - `source` string — Extraction source: llm, form_field, table
      - `source_document_id` string — Provenance: tracks which document and pipeline produced this attribute
      - `source_pipeline` string — Pipeline that produced this spec: mistral-ocr, technical-drawing, cad-worker, manual
      - `suggested_canonical` ModelsSuggestedCatalogAttribute
        - `aliases` string[] — Alternative names / aliases for this property
        - `property_description` string — Human-readable description of the property
        - `property_name` string — Suggested canonical property name
        - `unit` string — Suggested unit for the property
        - `value_examples` string[] — Example values for this property
        - `value_type` string — Expected value type (scalar, range, etc.)
      - `symbol` string — GD&T or engineering symbol (e.g., ⌀, ⊥, Ra)
      - `tolerance` string — Tolerance as written (e.g., "±0.1", "DIN ISO 2768-mk"); model-extract part-analysis
      - `ucum_unit` string — UCUM unit derived from original_unit by spec-worker
      - `value_type` string — Value type: scalar, range, vector, categorical, text
    - `title` string
    - `updated_at` string
  - `item2` ModelsItemComparisonSide
    - `category` string
    - `created_at` string
    - `id` string
    - `internal_code` string — drawing internal code (Kacher-test); small identifier line
    - `is_preferred` boolean
    - `manufacturer` string
    - `part_number` string
    - `references` string[]
    - `source_documents` ModelsSourceDocumentInfo[]
      - `classification` string — Document classification (e.g. datasheet, technical_drawing)
      - `filename` string — Display filename (path prefix stripped)
      - `id` string — Document ID
      - `mesh_url` string — Signed URL for the GLB 3D preview mesh
      - `mime_type` string — MIME type (e.g. application/pdf, model/jt)
      - `status` string — Document processing status
      - `tables` ModelsDocumentTable[] — Extracted content from document
        - `headers` string[] — Table column headers
        - `id` string — Table UUID
        - `page_number` integer — Page number where table was found
        - `rows` array[] — Table data rows
          - string[]
        - `table_index` integer — Index of table on the page (0-based)
      - `url` string — Signed URL for document access
    - `specifications` ModelsMatchedSpec[]
      - `canonical_name` string — Canonical attribute name (e.g., "input_voltage_max")
      - `canonical_unit` string — Catalog's expected unit (distinct from ucum_unit)
      - `confidence` number — Match confidence (0-1)
      - `count` string — Number of like features (e.g., "4" identical holes); model-extract part-analysis
      - `extracted_at` string — ISO 8601 timestamp when this spec was extracted
      - `match_method` string — How spec was matched to canonical name
      - `normalized_value` unknown
      - `original_key` string — Attribute name in English (translated from raw_key if non-English)
      - `original_unit` string — Original unit from document
      - `original_value` string — Value in English (translated from raw_value if non-English)
      - `page_number` integer — Page number in source document
      - `provisional_canonical` boolean — True when matched candidate has no confirmed canonical_name yet
      - `qualifier` string — Qualifier: min, max, typ, nominal
      - `qualifiers` string[] — Additional qualifiers (e.g., AC, DC)
      - `raw_key` string — Attribute name exactly as written in the document
      - `raw_value` string — Value exactly as written in the document
      - `registry_key_id` string — SHA-1 key_id from spec_key_registry
      - `rejected_match` string — LLM's suggestion when confidence was too low
      - `similarity_relevant` boolean — Model's per-spec flag for which features drive part matching (model-extract)
      - `source` string — Extraction source: llm, form_field, table
      - `source_document_id` string — Provenance: tracks which document and pipeline produced this attribute
      - `source_pipeline` string — Pipeline that produced this spec: mistral-ocr, technical-drawing, cad-worker, manual
      - `suggested_canonical` ModelsSuggestedCatalogAttribute
        - `aliases` string[] — Alternative names / aliases for this property
        - `property_description` string — Human-readable description of the property
        - `property_name` string — Suggested canonical property name
        - `unit` string — Suggested unit for the property
        - `value_examples` string[] — Example values for this property
        - `value_type` string — Expected value type (scalar, range, etc.)
      - `symbol` string — GD&T or engineering symbol (e.g., ⌀, ⊥, Ra)
      - `tolerance` string — Tolerance as written (e.g., "±0.1", "DIN ISO 2768-mk"); model-extract part-analysis
      - `ucum_unit` string — UCUM unit derived from original_unit by spec-worker
      - `value_type` string — Value type: scalar, range, vector, categorical, text
    - `title` string
    - `updated_at` string
  - `matching_specs` integer — Summary statistics. MatchingSpecs counts only identical rows; values that are merely similar (including numeric values within tolerance) count in CloseSpecs.
  - `only_in_item1` integer
  - `only_in_item2` integer
  - `reason` string
  - `similarity` ModelsSimilarityScores
    - `additional_score` number — similarity over the other measurements (0-1)
    - `exact_manufacturer_match` boolean — True if manufacturers match exactly
    - `exact_part_number_match` boolean — Flags for exact/tolerance matches
    - `fit` boolean — Two-stage compare (model_extraction tenant only): a SEPARATE additional score over the other part measurements (surface roughness, material, weight, bending radius), computed only when the important specs "fit". Deliberately NOT folded into WeightedTotal, so the primary score/classification is identical for every tenant.
    - `has_additional` boolean — an additional (other-measurements) score was computed
    - `manufacturer_score` number — Manufacturer similarity (0-1)
    - `part_number_score` number — Part number similarity (0-1)
    - `specifications_score` number — Specifications similarity (0-1)
    - `specs_within_tolerance` boolean — True if key specs (mass, dimensions) are within tolerance
    - `title_score` number — Title semantic similarity (0-1)
    - `weighted_total` number — Weighted total score (0-1)
  - `spec_diffs` ModelsSpecDiff[] — Spec differences (for easy UI rendering)
    - `canonical_name` string — Canonical spec name (e.g., "input_voltage_max")
    - `display_name` string — Human-readable name (e.g., "Input Voltage Max")
    - `is_numeric` boolean — IsNumeric is true when at least one value pair was compared as numbers. False for values that only look numeric, e.g. the dimension triple "49.00 X 5.00 X .25" (see services.parseNumeric).
    - `item1_original_keys` string[] — Original spec titles in item 1
    - `item1_units` string[] — Units in item 1
    - `item1_values` string[] — Values in item 1 (nil if missing)
    - `item2_original_keys` string[] — Original spec titles in item 2
    - `item2_units` string[] — Units in item 2
    - `item2_values` string[] — Values in item 2 (nil if missing)
    - `percent_diff` number — PercentDiff is how far apart the values are, for numeric rows that are not a full match. Unsigned.
    - `similarity_pct` number — SimilarityPct is how similar the two sides of this row are, 0-100, where 100 means every value has an identical counterpart. Populated for shared rows only (nil for only_item1 / only_item2). Note this points the OPPOSITE way to PercentDiff.
    - `status` string — Status is "match" (every value has an identical counterpart), "close" (similar but not identical — including numeric values that are merely within tolerance), "mismatch", "only_item1" or "only_item2". The match/close/mismatch vocabulary matches PairClassComparisonRow.Status so the two compare tables on the page speak the same language.

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `404` — Not Found

---

[API](https://skmtc.net/resourcly/apis/resourcly-api.md) · [All operations](https://skmtc.net/resourcly/apis/resourcly-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/resourcly/resourcly-api/revisions/7f97d8cd0f1e/schema)
