{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/gunspec-io/json-schema/gunspec-io-firearm-list-item-schema.json",
  "title": "FirearmListItem",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/gunspec-io-openapi.json#/components/schemas/FirearmListItem",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "URL-safe slug identifying the firearm, e.g. `glock-g17-gen5`. Stable: it is what a mirror keys on."
    },
    "name": {
      "type": "string",
      "description": "Display name, as the maker writes it."
    },
    "manufacturerId": {
      "type": "string",
      "description": "Slug of the manufacturer that makes it. Resolve against `/v1/manufacturers/{id}`."
    },
    "categoryId": {
      "type": "string",
      "description": "Slug of the category it belongs to. Resolve against `/v1/categories`."
    },
    "yearIntroduced": {
      "type": [
        "integer",
        "null"
      ],
      "description": "Year it entered production or service. Null where the date is disputed or unknown."
    },
    "status": {
      "anyOf": [
        {
          "$ref": "#/$defs/FirearmStatus"
        },
        {
          "type": "null"
        }
      ],
      "description": "Production status, one of `in_production`, `discontinued`, `out_of_production`, `in_service`, `limited_production`, `prototype`. Discontinued records are kept deliberately: a rifle built in 2004 wears parts nobody sells today."
    },
    "countryOfOrigin": {
      "type": [
        "string",
        "null"
      ],
      "description": "ISO 3166-1 alpha-2 code of where it was designed, e.g. `AT`."
    },
    "actionType": {
      "type": [
        "string",
        "null"
      ],
      "x-gunspec-vocabulary": [
        "short_recoil",
        "bolt_action",
        "blowback",
        "break_action",
        "gas_operated",
        "gas_operated_long_stroke",
        "gas_operated_direct_impingement",
        "revolving",
        "gas_operated_short_stroke",
        "muzzleloader",
        "pump_action",
        "lever_action",
        "double_action",
        "falling_block",
        "roller_delayed_blowback",
        "single_action",
        "gas_operated_short_stroke_piston",
        "single_action_revolver",
        "double_action_revolver",
        "inertia_operated",
        "recoil_operated",
        "delayed_blowback",
        "long_recoil",
        "gas_operated_rotating_bolt",
        "breech_loading",
        "rolling_block",
        "straight_pull",
        "trapdoor",
        "spring_piston",
        "hinged_breechblock",
        "lever_delayed_blowback",
        "blow_forward",
        "electric_gatling",
        "double_action_only",
        "rotating_barrel",
        "pneumatic",
        "gas_operated_dual_mode",
        "delayed_blowback_rotating_barrel",
        "gas_delayed_blowback",
        "radial_delayed_blowback",
        "short_recoil_rotating_barrel",
        "gas_operated_balanced_automatics",
        "gas_operated_balanced_recoil",
        "gas_operated_blow_forward",
        "gas_operated_open_bolt",
        "gas_operated_tilting_bolt"
      ],
      "description": "How the action cycles: `short_recoil`, `gas_operated`, `blowback`, `bolt_action` and so on. An open vocabulary: the values in use are published on the schema as `x-gunspec-vocabulary`, and `GET /v1/firearms/action-types` is the live list."
    },
    "weightEmptyG": {
      "type": [
        "number",
        "null"
      ],
      "description": "Unloaded weight in grams, without magazine."
    },
    "barrelLengthMm": {
      "type": [
        "number",
        "null"
      ],
      "description": "Barrel length in millimetres, measured from the breech face."
    },
    "images": {
      "type": "array",
      "description": "Every image this firearm has, silhouette first. Empty when none are on file.",
      "items": {
        "$ref": "#/$defs/InlineMediaItem"
      }
    },
    "createdAt": {
      "type": "string",
      "description": "When the record was first added, `YYYY-MM-DD HH:MM:SS` in UTC."
    },
    "svgLineArtUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "Line-art silhouette, or null where none has been drawn."
    },
    "model3dUrl": {
      "type": [
        "string",
        "null"
      ],
      "description": "GLB model, or null where none is on file."
    },
    "favoriteCount": {
      "type": "integer",
      "description": "How many accounts have favorited this record."
    },
    "updatedAt": {
      "type": "string",
      "description": "When a field we serve last changed. Maintained by the database rather than by whatever wrote the row, so it moves for a corrected specification and does not move for a re-run of the importer."
    },
    "version": {
      "type": [
        "string",
        "null"
      ],
      "description": "Opaque fingerprint of this record. It changes when and only when a field we serve changes, so a client holding the same value already has the record and need not fetch it. Equality is the only supported operation: do not parse it, and do not assume how it is computed. Null means the record has not been written since versioning began, not that it is unchanged."
    }
  },
  "$defs": {
    "FirearmStatus": {
      "type": "string",
      "enum": [
        "in_production",
        "discontinued",
        "out_of_production",
        "in_service",
        "limited_production",
        "prototype"
      ],
      "description": "Production status of a firearm. Closed: these are every value the catalog holds."
    },
    "InlineMediaItem": {
      "type": "object",
      "description": "One image attached to a firearm, inlined on list-shaped responses so a client can render a gallery without a second request. `url` is absolute and directly fetchable. For the full envelope, including credits, licence, dimensions and data-URI encoding, use `/v1/firearms/{id}/media`.",
      "properties": {
        "id": {
          "type": "integer",
          "description": "Autoincrementing image id."
        },
        "url": {
          "type": "string",
          "description": "Absolute, directly fetchable URL."
        },
        "kind": {
          "$ref": "#/$defs/MediaKind"
        },
        "alt": {
          "type": [
            "string",
            "null"
          ],
          "description": "Alt text, where one has been written. Null otherwise, so do not render an empty string."
        },
        "width": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Pixel width, where it is known."
        },
        "height": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Pixel height, where it is known."
        }
      },
      "required": [
        "id",
        "url",
        "kind"
      ]
    },
    "MediaKind": {
      "type": "string",
      "enum": [
        "silhouette",
        "render",
        "photo",
        "schematic",
        "model"
      ],
      "description": "What kind of asset a media row is."
    }
  }
}