{
  "openapi": "3.1.0",
  "info": {
    "title": "STH API",
    "version": "1.0.0",
    "description": "API to reach STH programmatically. Authenticate with a Bearer API key."
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key obtained from AssetGym Settings > API Keys"
      }
    },
    "schemas": {
      "VaultFileListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/VaultFileList"
          }
        },
        "required": [
          "data"
        ]
      },
      "VaultFileList": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/VaultFile"
        }
      },
      "VaultFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Short UUID of the file",
            "example": "mMxzWbBDSfiEP6MBcfNUgP"
          },
          "name": {
            "type": "string",
            "description": "Original file name",
            "example": "report.pdf"
          },
          "mime_type": {
            "type": "string",
            "description": "MIME type",
            "example": "application/pdf"
          },
          "size_bytes": {
            "type": "integer",
            "description": "File size in bytes",
            "example": 102400
          },
          "last_downloaded_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 timestamp of last download",
            "example": "2026-04-20T10:30:00.000Z"
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 creation timestamp",
            "example": "2026-04-15T08:00:00.000Z"
          },
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "Short-lived presigned URL to download the file. Valid until `download_url_expires_at`.",
            "example": "https://s3.eu-west-1.amazonaws.com/bucket/asset-vault/user-123/file-456/upload.pdf?X-Amz-Signature=..."
          },
          "download_url_expires_at": {
            "type": "string",
            "description": "ISO 8601 UTC timestamp when `download_url` stops working.",
            "example": "2026-04-29T13:30:00.000Z"
          }
        },
        "required": [
          "id",
          "name",
          "mime_type",
          "size_bytes",
          "last_downloaded_at",
          "created_at",
          "download_url",
          "download_url_expires_at"
        ]
      },
      "ApiKeyMissingError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "api_key_missing"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ApiKeyInvalidError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "api_key_invalid"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "PermissionDeniedError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "permission_denied"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "RateLimitExceededError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "rate_limit_exceeded"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "InternalErrorError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "internal_error"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "validation_failed"
                ]
              },
              "message": {
                "type": "string",
                "example": "Request validation failed"
              },
              "issues": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ErrorIssue"
                }
              }
            },
            "required": [
              "code",
              "message",
              "issues"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "ErrorIssue": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "Dotted path to the offending field, including array indices (e.g. `addon_types.0`). Empty string for top-level errors.",
            "example": "asset_type_code"
          },
          "code": {
            "type": "string",
            "enum": [
              "required",
              "invalid_type",
              "invalid_value",
              "out_of_range",
              "custom"
            ],
            "description": "Closed-set programmatic identifier for the issue type.",
            "example": "required"
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the issue.",
            "example": "Required"
          }
        },
        "required": [
          "path",
          "code",
          "message"
        ]
      },
      "CatalogSuggestResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogSuggestion"
            },
            "description": "Ranked list of suggestions. Capped to at most 5 entries."
          }
        },
        "required": [
          "data"
        ]
      },
      "CatalogSuggestion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the underlying entity. When `entity_type` = 'asset' this is the `asset_id`; when 'taxonomy' it is the `taxonomy_id`.",
            "example": 1234
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "taxonomy",
              "asset"
            ],
            "description": "`taxonomy` matches any taxonomy level; `asset` matches manufacturers and individual assets.",
            "example": "asset"
          },
          "display_name": {
            "type": "string",
            "description": "Friendly display string for the row. For asset (leaf) rows this is the full concatenated chain (e.g. `\"Caterpillar 320 GC\"`); for taxonomy and manufacturer rows it is the bare entity name (e.g. `\"Excavators\"`, `\"Caterpillar\"`).",
            "example": "Caterpillar 320 GC"
          },
          "asset_chain": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogChainNode"
            },
            "description": "Chain through the assets tree ordered from the root down to the row itself: manufacturer first, the row last (e.g. `[\"Komatsu\", \"PC\", \"210-7\"]`). Always `[]` for taxonomy rows (their chain is in `taxonomy_chain`)."
          },
          "taxonomy_chain": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogChainNode"
            },
            "description": "Chain through the taxonomy tree ordered from the root down: broadest category first, leaf last. For taxonomy rows this is the row's own chain (ending in the row itself); for asset rows it is the classification chain, populated only when the asset carries its own taxonomy."
          }
        },
        "required": [
          "id",
          "entity_type",
          "display_name",
          "asset_chain",
          "taxonomy_chain"
        ]
      },
      "CatalogChainNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the node (asset_id or taxonomy_id).",
            "example": 100
          },
          "name": {
            "type": "string",
            "description": "Name of the chain node.",
            "example": "Caterpillar"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "CatalogSuggestRequest": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Free-text term that is being searched.",
            "example": "komatsu pc210"
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "taxonomy",
              "asset"
            ],
            "description": "Restrict results to a single domain. Omit to return both.",
            "example": "asset"
          },
          "parent_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 2147483647,
            "description": "Scope to the subtree below this asset. By default every descendant is searched; set `direct_only=true` to search only the direct children. Cannot be combined with `entity_type=\"taxonomy\"` (taxonomy rows are not part of the assets tree).",
            "example": 1234
          },
          "taxonomy_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 2147483647,
            "description": "Classification scope. Asset and manufacturer rows match when anything in their subtree is classified at or under this taxonomy. Taxonomy rows match when they are this taxonomy or one of its descendants; or, with `direct_only=true` (and no `parent_id`), exactly its direct child taxonomies.",
            "example": 56
          },
          "direct_only": {
            "type": "boolean",
            "description": "Search only the first level of the scope. With `parent_id`: the direct children of that asset. With `taxonomy_id` (and no `parent_id`): its direct child taxonomies, plus manufacturers whose subtree intersects the taxonomy. With no scope: tree roots only (industries and manufacturers). Defaults to `false` (full depth).",
            "example": false
          }
        },
        "required": [
          "query"
        ],
        "additionalProperties": false
      },
      "CatalogTaxonomyListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogTaxonomyNode"
            },
            "description": "Page of taxonomy nodes."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total count after filters, before paging. Only present when `include_total=true` was passed.",
            "example": 14
          }
        },
        "required": [
          "data"
        ]
      },
      "CatalogTaxonomyNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the taxonomy node.",
            "example": 12
          },
          "name": {
            "type": "string",
            "description": "Name of the taxonomy.",
            "example": "Excavators"
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "Direct parent id, or `null` for a root taxonomy.",
            "example": 3
          }
        },
        "required": [
          "id",
          "name",
          "parent_id"
        ]
      },
      "NotFoundError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "not_found"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "CatalogAssetListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogAssetNode"
            },
            "description": "Page of asset nodes."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total count after filters, before paging. Only present when `include_total=true` was passed.",
            "example": 42
          }
        },
        "required": [
          "data"
        ]
      },
      "CatalogAssetNode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset node.",
            "example": 1234
          },
          "name": {
            "type": "string",
            "description": "Name of the asset.",
            "example": "210-7"
          },
          "qualified_name": {
            "type": "string",
            "description": "Name prefixed with all ancestor names, space-separated (e.g. `Komatsu PC 210-7`).",
            "example": "Komatsu PC 210-7"
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "Direct parent asset id, or `null` for a manufacturer.",
            "example": 100
          }
        },
        "required": [
          "id",
          "name",
          "qualified_name",
          "parent_id"
        ]
      },
      "IdentifyResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IdentificationMatch"
            },
            "description": "Potential matches across all provided inputs, ranked best first: matches supported by more inputs rank above single-input matches, deterministic serial decodes rank above probabilistic ones, and probabilistic matches are ordered by `confidence`. Empty when nothing matched. Each match identifies the asset axis, the taxonomy axis, or both. Capped to at most 5 entries."
          },
          "photo": {
            "$ref": "#/components/schemas/PhotoReading"
          }
        },
        "required": [
          "data"
        ]
      },
      "IdentificationMatch": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "Id of the identified node in the assets tree, or `null` when the evidence did not resolve to anything on the asset axis. Can be any level of the tree: a manufacturer when only the maker was recognized, or a model when the match is precise. At least one of `asset_id` and `taxonomy_id` is set.",
            "example": 1234
          },
          "taxonomy_id": {
            "type": [
              "integer",
              "null"
            ],
            "exclusiveMinimum": 0,
            "description": "Id of the identified taxonomy node, or `null` when the kind of machine could not be determined. At least one of `asset_id` and `taxonomy_id` is set.",
            "example": 56
          },
          "asset_display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Friendly display string for the asset axis: the full concatenated asset chain (e.g. `\"Caterpillar 320 GC\"`, or just `\"Caterpillar\"` for a manufacturer-level match). `null` when `asset_id` is `null`.",
            "example": "Caterpillar 320 GC"
          },
          "taxonomy_display_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Friendly display string for the taxonomy axis: the bare taxonomy name (e.g. `\"Crawler excavator\"`). `null` when `taxonomy_id` is `null`.",
            "example": "Crawler excavator"
          },
          "basis": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "description",
                "serial_number",
                "photo"
              ],
              "description": "A request input that contributed to a match. `serial_number` refers to the serial sent as a field; `photo` to the serial (and text) read off the uploaded photo.",
              "example": "serial_number"
            },
            "minItems": 1,
            "description": "The request inputs that support this match, in the order `description`, `serial_number`, `photo`. A match supported by several inputs at once ranks above single-input matches.",
            "example": [
              "serial_number"
            ]
          },
          "confidence": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Match confidence between 0 and 1 for probabilistic evidence (a description). `null` when the match rests purely on deterministic serial decoding; those matches carry an `explanation` instead and rank first. Thresholds are up to the client; values above 0.9 are usually safe to auto-accept.",
            "example": 0.93
          },
          "explanation": {
            "type": [
              "string",
              "null"
            ],
            "description": "Prepared English explanation of how the serial number was decoded into this match, assembled from `explanation_segments`; safe to show to end users. `null` when no serial contributed to the match.",
            "example": "Characters 1–3 “CAT” identify Caterpillar. Characters 4–9 “0320GC” identify the 320 GC model line. Character 11 “A” encodes the 2019 model year."
          },
          "explanation_segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SerialExplanationSegment"
            },
            "description": "Programmatic serial-decoding derivation, ordered by `position_start`. Each segment states which characters were read and what they resolved to. Deterministic: the same serial always yields the same segments. Positions are 1-indexed into the serial number: the `serial_number` request field, or `photo.serial_number` when the serial was read off a photo. `[]` when no serial contributed to the match."
          },
          "asset_chain": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogChainNode"
            },
            "description": "Chain through the assets tree ordered from the root down: the manufacturer first, the identified node last. `[]` when `asset_id` is `null`."
          },
          "taxonomy_chain": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogChainNode"
            },
            "description": "Chain through the taxonomy tree ordered from the root down: the broadest category first, the identified taxonomy last. `[]` when `taxonomy_id` is `null`."
          }
        },
        "required": [
          "asset_id",
          "taxonomy_id",
          "asset_display_name",
          "taxonomy_display_name",
          "basis",
          "confidence",
          "explanation",
          "explanation_segments",
          "asset_chain",
          "taxonomy_chain"
        ]
      },
      "SerialExplanationSegment": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "manufacturer",
              "model",
              "model_year",
              "plant",
              "sequence"
            ],
            "description": "What a decoded serial segment encodes. `manufacturer`: the maker; `model`: the model or model line; `model_year`: the production year code; `plant`: the factory of origin; `sequence`: the per-unit production sequence (identifies the individual machine, not decoded further).",
            "example": "manufacturer"
          },
          "characters": {
            "type": "string",
            "description": "The exact characters of the serial number this segment covers.",
            "example": "CAT"
          },
          "position_start": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "1-indexed position of the segment's first character within the serial number.",
            "example": 1
          },
          "position_end": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "1-indexed position of the segment's last character (inclusive).",
            "example": 3
          },
          "resolved_value": {
            "type": "string",
            "description": "What the segment resolves to, human-readable: a manufacturer name for `manufacturer`, a model line for `model`, a year for `model_year`. For `sequence` segments this is the sequence itself.",
            "example": "Caterpillar"
          }
        },
        "required": [
          "kind",
          "characters",
          "position_start",
          "position_end",
          "resolved_value"
        ]
      },
      "PhotoReading": {
        "type": "object",
        "properties": {
          "serial_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "The serial number as read off the photo, normalized (uppercase, no spaces), or `null` when the photo contains no readable serial. Show it to the end user for confirmation; if the read is slightly wrong, correct it and re-identify with the `serial_number` field. When `null` and no other input was provided, `data` is empty; there is no error status for an unreadable serial.",
            "example": "CAT0320GC-A9K02154"
          },
          "serial_number_confidence": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Confidence of the photo read between 0 and 1, or `null` when no serial was read. It scores the reading of the characters, not the matches: decoding the read serial into assets is deterministic and unscored. Low values mean the serial may have been misread; confirm `serial_number` with the end user before trusting the matches.",
            "example": 0.97
          },
          "image_width": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Width in pixels of the photo as processed, after EXIF orientation was applied (the orientation a browser displays by default). Annotation coordinates are fractions of this frame; compare against your rendered image to detect an orientation mismatch.",
            "example": 3024
          },
          "image_height": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Height in pixels of the photo as processed, after EXIF orientation was applied.",
            "example": 4032
          },
          "text_annotations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PhotoTextAnnotation"
            },
            "description": "Every text region recognized in the photo, in reading order (top to bottom), with normalized bounding rectangles for drawing an overlay on the uploaded image: multiply `x`/`width` by the rendered width and `y`/`height` by the rendered height. Coordinates are relative to the EXIF-oriented image (origin top-left). Regions with `is_serial_number: true` are the ones the serial was read from."
          }
        },
        "required": [
          "serial_number",
          "serial_number_confidence",
          "image_width",
          "image_height",
          "text_annotations"
        ],
        "description": "What was read off the uploaded photo. Present exactly when the request carried a `photo`; absent for JSON requests."
      },
      "PhotoTextAnnotation": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Recognized text verbatim as it appears in the photo, including spacing and label prefixes as printed. For serial regions this may differ from `photo.serial_number`, which is normalized for matching.",
            "example": "CAT 0320GC-A 9K02154"
          },
          "is_serial_number": {
            "type": "boolean",
            "description": "`true` when this region is (part of) the serial number that was read. A serial stamped across several lines yields several regions with this flag; concatenated in array order they form the read that `photo.serial_number` was normalized from.",
            "example": true
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Recognition confidence for this region's text, between 0 and 1.",
            "example": 0.97
          },
          "x": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Left edge of the bounding rectangle as a fraction of image width (0 = left edge, 1 = right edge).",
            "example": 0.38
          },
          "y": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Top edge of the bounding rectangle as a fraction of image height (0 = top edge, 1 = bottom edge).",
            "example": 0.535
          },
          "width": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Width of the bounding rectangle as a fraction of image width.",
            "example": 0.35
          },
          "height": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Height of the bounding rectangle as a fraction of image height.",
            "example": 0.032
          }
        },
        "required": [
          "text",
          "is_serial_number",
          "confidence",
          "x",
          "y",
          "width",
          "height"
        ]
      },
      "IdentifyRequest": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "minLength": 3,
            "maxLength": 500,
            "description": "Free-text description of the asset as it appears in your source system: dealer feeds, spreadsheets, invoices. Abbreviations, mixed languages, and noise are expected.",
            "example": "cat 320gc escavatore cingolato 2019 usato"
          },
          "serial_number": {
            "type": "string",
            "minLength": 3,
            "maxLength": 100,
            "description": "Serial number as stamped on the asset's identification plate.",
            "example": "CAT0320GC-A9K02154"
          },
          "manufacturer_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Optional asset id of a manufacturer (a root node of the assets tree) to constrain serial decoding. A scope, not evidence: it narrows the search, it is not billed, and it never appears in `basis`. Unknown ids return `404 not_found`.",
            "example": 100
          }
        },
        "additionalProperties": false
      },
      "IdentifyPhotoRequest": {
        "type": "object",
        "properties": {
          "photo": {
            "type": "string",
            "format": "binary",
            "description": "Photo showing the asset's serial number: an identification plate, a stamped frame, a sticker. JPEG, PNG, WebP, or HEIC/HEIF, at most 10 MB."
          },
          "description": {
            "type": "string",
            "minLength": 3,
            "maxLength": 500,
            "description": "Free-text description of the asset as it appears in your source system: dealer feeds, spreadsheets, invoices. Abbreviations, mixed languages, and noise are expected.",
            "example": "cat 320gc escavatore cingolato 2019 usato"
          },
          "serial_number": {
            "type": "string",
            "minLength": 3,
            "maxLength": 100,
            "description": "Serial number as stamped on the asset's identification plate.",
            "example": "CAT0320GC-A9K02154"
          },
          "manufacturer_id": {
            "type": "integer",
            "description": "Optional asset id of a manufacturer (a root node of the assets tree) to constrain serial decoding. A scope, not evidence: it narrows the search, it is not billed, and it never appears in `basis`. Unknown ids return `404 not_found`. Sent as a text form field.",
            "example": 100
          }
        },
        "required": [
          "photo"
        ],
        "additionalProperties": false
      },
      "OperationCo2": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset the figures belong to.",
            "example": 1234
          },
          "co2_per_unit": {
            "type": [
              "number",
              "null"
            ],
            "description": "Operational CO2e emitted per usage unit (see `co2_unit`).",
            "example": 32.7
          },
          "co2_unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit of `co2_per_unit`.",
            "example": "kg/h"
          },
          "co2_per_year": {
            "type": [
              "number",
              "null"
            ],
            "description": "Operational CO2e per year in kilograms, computed from `co2_per_unit` and the typical yearly usage.",
            "example": 58860
          },
          "yearly_usage_amount": {
            "type": [
              "number",
              "null"
            ],
            "description": "Typical yearly usage assumed for `co2_per_year`.",
            "example": 1800
          },
          "yearly_usage_unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit of `yearly_usage_amount`.",
            "example": "h/year"
          },
          "fuel_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fuel or energy carrier of the asset. Multi-fuel assets list every carrier slash-joined (e.g. `petrol/electric`).",
            "example": "diesel"
          },
          "fuel_consumptions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FuelConsumption"
            },
            "description": "Consumption figures backing the CO2 numbers. Empty when not available."
          }
        },
        "required": [
          "asset_id",
          "co2_per_unit",
          "co2_unit",
          "co2_per_year",
          "yearly_usage_amount",
          "yearly_usage_unit",
          "fuel_type",
          "fuel_consumptions"
        ]
      },
      "FuelConsumption": {
        "type": "object",
        "properties": {
          "fuel_type": {
            "type": "string",
            "description": "Fuel or energy carrier this consumption entry refers to.",
            "example": "diesel"
          },
          "consumption": {
            "type": "number",
            "description": "Consumption amount per `consumption_unit`.",
            "example": 12.4
          },
          "consumption_unit": {
            "type": "string",
            "description": "Unit of the consumption amount.",
            "example": "l/h"
          },
          "source": {
            "type": "string",
            "description": "Provenance of this figure. `asset` is a value recorded for this exact asset and `asset_representative_descendant` comes from a representative descendant asset, while `taxonomy_*` values are calculated from the asset's classification (for example `taxonomy_specification_power_adjusted` is the taxonomy figure scaled to this asset's engine power). New values may be added over time.",
            "example": "asset"
          }
        },
        "required": [
          "fuel_type",
          "consumption",
          "consumption_unit",
          "source"
        ]
      },
      "ProductionCo2": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset the figures belong to.",
            "example": 1234
          },
          "material_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "Embodied emissions of the asset's materials, in kg CO2e.",
            "example": 78100
          },
          "energy_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "Manufacturing-energy emissions, in kg CO2e.",
            "example": 18300
          },
          "total_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "Total production emissions (materials + manufacturing energy), in kg CO2e.",
            "example": 96400
          },
          "material_composition": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialCompositionEntry"
            },
            "description": "Material breakdown of the asset, ordered by share, largest first. Empty when not available."
          }
        },
        "required": [
          "asset_id",
          "material_kgco2e",
          "energy_kgco2e",
          "total_kgco2e",
          "material_composition"
        ]
      },
      "MaterialCompositionEntry": {
        "type": "object",
        "properties": {
          "material": {
            "type": "string",
            "description": "Material name.",
            "example": "steel"
          },
          "mass_kg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Mass of this material in the asset, in kilograms. `null` when only the share is known.",
            "example": 15330
          },
          "share": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Fraction of the asset's total mass, between 0 and 1.",
            "example": 0.7
          }
        },
        "required": [
          "material",
          "mass_kg",
          "share"
        ]
      },
      "EndOfLifeCo2": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset the figures belong to.",
            "example": 1234
          },
          "recycling_emissions_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "Emissions caused by the recycling process itself, in kg CO2e.",
            "example": 4100
          },
          "recycling_credit_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "Avoided-burden credit for recovered materials, in kg CO2e. Positive number; subtract it from the emissions.",
            "example": 12600
          },
          "net_kgco2e": {
            "type": [
              "number",
              "null"
            ],
            "description": "`recycling_emissions_kgco2e` minus `recycling_credit_kgco2e`. Negative when recycling is a net benefit.",
            "example": -8500
          },
          "material_composition": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaterialCompositionEntry"
            },
            "description": "Material breakdown of the asset, ordered by share, largest first. Empty when not available."
          }
        },
        "required": [
          "asset_id",
          "recycling_emissions_kgco2e",
          "recycling_credit_kgco2e",
          "net_kgco2e",
          "material_composition"
        ]
      },
      "TechnicalSpecification": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset the specification belongs to.",
            "example": 1234
          },
          "weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Operating weight in kilograms.",
            "example": 21900
          },
          "engine_power_kw": {
            "type": [
              "number",
              "null"
            ],
            "description": "Rated engine power in kilowatts.",
            "example": 122
          },
          "fuel_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Fuel or energy carrier of the asset. Multi-fuel assets list every carrier slash-joined (e.g. `petrol/electric`).",
            "example": "diesel"
          }
        },
        "required": [
          "asset_id",
          "weight_kg",
          "engine_power_kw",
          "fuel_type"
        ]
      },
      "TechnicalSpecificationAttributeListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TechnicalSpecificationAttribute"
            },
            "description": "Page of the asset's technical specification attributes."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total count before paging. Only present when `include_total=true` was passed.",
            "example": 12
          }
        },
        "required": [
          "data"
        ]
      },
      "TechnicalSpecificationAttribute": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Canonical attribute key, stable across assets and shared with the taxonomy vocabulary: join asset values to taxonomy definitions on this field. For numeric attributes the normalized unit is part of the key (e.g. `dig_depth_mm`). The key set is data, not schema: keys may be added, merged, or retired as document coverage grows.",
            "example": "dig_depth_mm"
          },
          "label": {
            "type": "string",
            "description": "Canonical human-readable label of the attribute, identical for every asset.",
            "example": "Maximum digging depth"
          },
          "value": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Normalized value: a number for numeric attributes (in the attribute's canonical unit) or a string for textual ones, matching the `data_type` the taxonomy vocabulary declares for this `key`.",
            "example": 6720
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit of the normalized value. `null` for unitless (e.g. textual) attributes. Fixed per `key`: every asset reports this attribute in the same unit.",
            "example": "mm"
          }
        },
        "required": [
          "key",
          "label",
          "value",
          "unit"
        ]
      },
      "TaxonomyTechnicalSpecificationAttributeListResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaxonomyTechnicalSpecificationAttribute"
            },
            "description": "Page of the taxonomy's attribute vocabulary, ordered by descending `coverage`."
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Total count before paging. Only present when `include_total=true` was passed.",
            "example": 8
          }
        },
        "required": [
          "data"
        ]
      },
      "TaxonomyTechnicalSpecificationAttribute": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Canonical attribute key, stable across assets and shared with the taxonomy vocabulary: join asset values to taxonomy definitions on this field. For numeric attributes the normalized unit is part of the key (e.g. `dig_depth_mm`). The key set is data, not schema: keys may be added, merged, or retired as document coverage grows.",
            "example": "dig_depth_mm"
          },
          "label": {
            "type": "string",
            "description": "Canonical human-readable label of the attribute, identical for every asset.",
            "example": "Maximum digging depth"
          },
          "data_type": {
            "type": "string",
            "enum": [
              "number",
              "string"
            ],
            "description": "Type of the `value` asset entries carry for this key. New types may be added over time.",
            "example": "number"
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit of the normalized value. `null` for unitless (e.g. textual) attributes. Fixed per `key`: every asset reports this attribute in the same unit.",
            "example": "mm"
          },
          "coverage": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "How common this attribute is in the taxonomy's documentation: the fraction of documented assets under this node (those with processed manufacturer documentation) that have a value for it, between 0 and 1. Use it to pick comparison columns (e.g. keep keys with coverage >= 0.8). Note that an asset without processed documentation returns no value even for high-coverage keys.",
            "example": 0.91
          }
        },
        "required": [
          "key",
          "label",
          "data_type",
          "unit",
          "coverage"
        ]
      },
      "GeoContent": {
        "type": "object",
        "properties": {
          "asset_id": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "description": "Id of the asset the content belongs to.",
            "example": 1234
          },
          "summary": {
            "type": [
              "string",
              "null"
            ],
            "description": "One-sentence plain-text summary of the asset.",
            "example": "The Caterpillar 320 GC is a 21.9-tonne crawler excavator built for lower-cost-per-hour production work."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Long-form plain-text description of the asset. Paragraphs separated by blank lines.",
            "example": "The Caterpillar 320 GC pairs a 122 kW engine with a reduced-power hydraulic system…"
          },
          "highlights": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Short bullet-style facts about the asset. Empty when not available."
          },
          "applications": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Typical applications and industries the asset is used in. Empty when not available."
          }
        },
        "required": [
          "asset_id",
          "summary",
          "description",
          "highlights",
          "applications"
        ]
      }
    }
  },
  "paths": {
    "/api/v1/vault-files": {
      "get": {
        "summary": "List asset vault files",
        "description": "Returns up to 50 asset vault files belonging to the authenticated user.",
        "tags": [
          "AssetVault"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Up to 50 vault files",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VaultFileListResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/suggest": {
      "post": {
        "summary": "Suggest catalog entries",
        "description": "Ranked autocomplete over the catalog (assets + taxonomies). Scope the results with `parent_id` (asset subtree), `taxonomy_id` (classification subtree), and `direct_only` (first level of the scope only; see each parameter for how they combine). Unlike the browse endpoints, scope ids are not existence-checked: an unknown id yields an empty result rather than a 404, keeping autocomplete responsive.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "query": "komatsu pc210",
                "entity_type": "asset",
                "parent_id": 1234
              },
              "schema": {
                "$ref": "#/components/schemas/CatalogSuggestRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked suggestions (0 to 5 entries)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogSuggestResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/taxonomies": {
      "get": {
        "summary": "List taxonomies",
        "description": "Paginated taxonomy list. If no `parent_id` is provided, returns root taxonomies. Pass `parent_id` to fetch direct children of a node.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Number of items to skip. Defaults to 0.",
              "example": 0
            },
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "in": "query",
            "name": "offset"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "description": "Number of items per page. Defaults to 50, capped at 100.",
              "example": 50
            },
            "required": false,
            "description": "Number of items per page. Defaults to 50, capped at 100.",
            "in": "query",
            "name": "limit"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false",
              "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
              "example": "false"
            },
            "required": false,
            "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
            "in": "query",
            "name": "include_total"
          },
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "List direct children of this taxonomy.",
              "example": 3
            },
            "required": false,
            "description": "List direct children of this taxonomy.",
            "in": "query",
            "name": "parent_id"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of taxonomy nodes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogTaxonomyListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Referenced `parent_id` does not exist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/taxonomies/{taxonomy_id}": {
      "get": {
        "summary": "Get a taxonomy",
        "description": "Fetch a single taxonomy node by id.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Taxonomy id.",
              "example": 12
            },
            "required": true,
            "description": "Taxonomy id.",
            "in": "path",
            "name": "taxonomy_id"
          }
        ],
        "responses": {
          "200": {
            "description": "The taxonomy node",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogTaxonomyNode"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Taxonomy not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets": {
      "get": {
        "summary": "List assets",
        "description": "Paginated asset list ordered by name. With no filters, returns top-level assets (manufacturers). `parent_id` and `taxonomy_id` each narrow the results (see each parameter); combining them returns the direct children of `parent_id` that also match the taxonomy filter.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Number of items to skip. Defaults to 0.",
              "example": 0
            },
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "in": "query",
            "name": "offset"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "description": "Number of items per page. Defaults to 50, capped at 100.",
              "example": 50
            },
            "required": false,
            "description": "Number of items per page. Defaults to 50, capped at 100.",
            "in": "query",
            "name": "limit"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false",
              "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
              "example": "false"
            },
            "required": false,
            "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
            "in": "query",
            "name": "include_total"
          },
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "List direct children of this asset.",
              "example": 100
            },
            "required": false,
            "description": "List direct children of this asset.",
            "in": "query",
            "name": "parent_id"
          },
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Include assets whose subtree contains anything classified under this taxonomy or its descendants.",
              "example": 12
            },
            "required": false,
            "description": "Include assets whose subtree contains anything classified under this taxonomy or its descendants.",
            "in": "query",
            "name": "taxonomy_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Page of assets (0 to `limit`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogAssetListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Referenced `parent_id` or `taxonomy_id` does not exist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}": {
      "get": {
        "summary": "Get an asset",
        "description": "Fetch a single asset node by id.",
        "tags": [
          "Catalog"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "The asset node",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogAssetNode"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/identify": {
      "post": {
        "summary": "Identify an asset",
        "x-preview": true,
        "description": "Identify a catalog asset from any combination of evidence: a free-text `description` (dealer feeds, spreadsheets, invoices), a `serial_number` as stamped on the identification plate, and/or a `photo` showing the serial. Send text-only evidence as `application/json`; include a photo by sending `multipart/form-data` with the image in the `photo` field and the other inputs as text form fields. At least one input is required. The response is one fused, ranked match list: every match declares which inputs support it (`basis`), matches supported by several inputs rank first, deterministic serial decodes carry an `explanation` with character-level `explanation_segments`, and probabilistic description matches carry a `confidence`. When a photo was sent, `photo` in the response echoes what was read off it: the normalized serial, its read confidence, and every recognized text region with a normalized bounding rectangle for drawing overlays. A photo with no readable serial is not an error: `photo.serial_number` is `null` and any other provided inputs still match. Pass `manufacturer_id` to constrain serial decoding when the same pattern is used by several manufacturers. Each provided input is billed additively at its own credit weight. Note: this is a preview endpoint that currently returns illustrative mock data; upload a zero-byte file to preview the unreadable-photo shape.",
        "tags": [
          "Identification"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "example": {
                "description": "cat 320gc escavatore cingolato 2019 usato"
              },
              "schema": {
                "$ref": "#/components/schemas/IdentifyRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/IdentifyPhotoRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked matches across all provided inputs (0 to 5 entries), plus the photo reading when a photo was sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentifyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Referenced `manufacturer_id` does not exist",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/co2/operation": {
      "get": {
        "summary": "Get operational CO2",
        "description": "Operational (use-phase) CO2 figures for the asset: emissions per usage unit and per year, with the fuel/energy consumption figures backing them. Fields are `null` where no data exists. Figures are served from a periodically refreshed snapshot, so recent catalog edits may take up to a day to appear.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Operational CO2 figures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OperationCo2"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/co2/production": {
      "get": {
        "summary": "Get production CO2",
        "description": "Production (cradle-to-gate) CO2 figures for the asset: embodied material emissions, manufacturing-energy emissions, and their total, in kg CO2e, plus the material composition the material emissions are based on. Material masses are derived from the asset's operating weight; when only shares are known, `mass_kg` is `null`. Fields are `null` where no data exists. Figures are served from a periodically refreshed snapshot, so recent catalog edits may take up to a day to appear.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Production CO2 figures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductionCo2"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/co2/end-of-life": {
      "get": {
        "summary": "Get end-of-life CO2",
        "x-preview": true,
        "description": "End-of-life CO2 figures for the asset: recycling-process emissions, the avoided-burden credit for recovered materials, and the net result, in kg CO2e, plus the material composition the recovery figures are based on. Fields are `null` where no data exists. Note: this is a preview endpoint that currently returns illustrative mock data.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "End-of-life CO2 figures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndOfLifeCo2"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/technical-specification": {
      "get": {
        "summary": "Get the technical specification",
        "description": "The asset's technical specification: operating weight, engine power, fuel type, and further typed spec fields as coverage grows. Fields are `null` where no data exists. Where a representative variant is designated for the asset, figures come from that variant's specification. Served directly from the catalog, so recent edits appear immediately.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "The technical specification",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TechnicalSpecification"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/technical-specification-attributes": {
      "get": {
        "summary": "List technical specification attributes",
        "x-preview": true,
        "description": "Every technical specification attribute extracted for the asset from manufacturer documentation: attributes shared across the asset's taxonomy and asset-specific ones alike. Values are normalized: each `key` is canonical with one fixed unit, so the same key is directly comparable across assets. To learn which keys are common for a taxonomy (e.g. to pick comparison columns), call `GET /catalog/taxonomies/{taxonomy_id}/technical-specification-attributes` and join on `key`. The key set is data, not schema: keys are added, merged, and retired as document coverage grows; ordering is stable per asset but unspecified, so join on `key`, not position. Note: this is a preview endpoint that currently returns illustrative mock data.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Number of items to skip. Defaults to 0.",
              "example": 0
            },
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "in": "query",
            "name": "offset"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "description": "Number of items per page. Defaults to 50, capped at 100.",
              "example": 50
            },
            "required": false,
            "description": "Number of items per page. Defaults to 50, capped at 100.",
            "in": "query",
            "name": "limit"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false",
              "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
              "example": "false"
            },
            "required": false,
            "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
            "in": "query",
            "name": "include_total"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the asset's technical specification attributes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TechnicalSpecificationAttributeListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/taxonomies/{taxonomy_id}/technical-specification-attributes": {
      "get": {
        "summary": "List taxonomy technical specification attributes",
        "x-preview": true,
        "description": "The technical-specification vocabulary of a taxonomy: every attribute key that appears on assets under this node, with its canonical label, value type, unit, and `coverage`. Coverage is how common the attribute is among the node's documented assets (those with processed manufacturer documentation). Use it to discover which attributes are common (and therefore comparable) across a taxonomy before fetching per-asset values from `GET /catalog/assets/{asset_id}/technical-specification-attributes`; the two join on `key`. Entries are ordered by descending `coverage`. Coverage is computed from a periodically refreshed snapshot, so recent catalog changes may take up to a day to appear. Note: this is a preview endpoint that currently returns illustrative mock data.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Taxonomy id.",
              "example": 12
            },
            "required": true,
            "description": "Taxonomy id.",
            "in": "path",
            "name": "taxonomy_id"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "description": "Number of items to skip. Defaults to 0.",
              "example": 0
            },
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "in": "query",
            "name": "offset"
          },
          {
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50,
              "description": "Number of items per page. Defaults to 50, capped at 100.",
              "example": 50
            },
            "required": false,
            "description": "Number of items per page. Defaults to 50, capped at 100.",
            "in": "query",
            "name": "limit"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false",
              "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
              "example": "false"
            },
            "required": false,
            "description": "Opt-in to a `total` field in the response. Defaults to `false`. Case-insensitive.",
            "in": "query",
            "name": "include_total"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of the taxonomy's attribute vocabulary, most common first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomyTechnicalSpecificationAttributeListResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Taxonomy not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/catalog/assets/{asset_id}/geo-content": {
      "get": {
        "summary": "Get GEO content",
        "x-preview": true,
        "description": "Editorial content about the asset written for generative-engine and search visibility: a summary, a long-form description, highlights, and typical applications. All fields are typed; text is plain text. Note: this is a preview endpoint that currently returns illustrative mock data.",
        "tags": [
          "Asset Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 2147483647,
              "description": "Asset id.",
              "example": 1234
            },
            "required": true,
            "description": "Asset id.",
            "in": "path",
            "name": "asset_id"
          }
        ],
        "responses": {
          "200": {
            "description": "GEO content for the asset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoContent"
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/ApiKeyMissingError"
                    },
                    {
                      "$ref": "#/components/schemas/ApiKeyInvalidError"
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required permission",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermissionDeniedError"
                }
              }
            }
          },
          "404": {
            "description": "Asset not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFoundError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; slow down and retry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitExceededError"
                }
              }
            }
          },
          "500": {
            "description": "Unhandled server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InternalErrorError"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {}
}