{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/hobbycardindex-com/json-schema/hobbycardindex-com-scan-response-schema.json",
  "title": "ScanResponse",
  "x-generated": "2026-11-11",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/hobbycardindex-com-openapi.json#/components/schemas/ScanResponse",
  "type": "object",
  "properties": {
    "match": {
      "oneOf": [
        {
          "allOf": [
            {
              "$ref": "#/$defs/ScanCard"
            },
            {
              "type": "object",
              "properties": {
                "prices": {
                  "oneOf": [
                    {
                      "$ref": "#/$defs/Prices"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "The best card, with its prices; null when nothing is close enough."
    },
    "alternatives": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/ScanCard"
      },
      "description": "Up to 7 more cards, without prices. Show them and let the user choose."
    },
    "engine": {
      "type": "string",
      "description": "`image` when our own image index answered, `vision` when the fallback model did."
    },
    "slab": {
      "oneOf": [
        {
          "$ref": "#/$defs/Slab"
        },
        {
          "type": "null"
        }
      ],
      "description": "The graded-card label, or null on a raw card."
    },
    "scanId": {
      "type": [
        "string",
        "integer",
        "null"
      ],
      "description": "Our id for this scan."
    },
    "uncertain": {
      "type": "boolean",
      "description": "True when the user should confirm the card, or its printing, before you show a price."
    },
    "printingUncertain": {
      "type": "boolean",
      "description": "True when the card is right but its printing (colour, parallel) is not certain. The alternatives usually hold the other printings."
    },
    "reason": {
      "type": "string",
      "enum": [
        "low_confidence",
        "no_card",
        "name_not_on_card"
      ],
      "description": "Why `match` is null: `low_confidence` (no card scored 0.75 or more), `no_card` (no card in the photo), `name_not_on_card` (the closest card's name is not printed on the card in the photo). The alternatives still come back."
    },
    "nameCheck": {
      "type": "string",
      "enum": [
        "match",
        "switched",
        "not_on_card",
        "no_match",
        "no_text",
        "skipped",
        "unavailable"
      ],
      "description": "On a match under 0.85: how the name printed on the card compared with the pick."
    },
    "usage": {
      "type": "object",
      "properties": {
        "scans": {
          "type": "object",
          "properties": {
            "used": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Scans used this month, after this one."
            },
            "allowance": {
              "type": "integer"
            }
          }
        }
      }
    }
  },
  "required": [
    "match",
    "alternatives",
    "engine"
  ],
  "additionalProperties": true,
  "$defs": {
    "PriceGrid": {
      "type": "object",
      "properties": {
        "loose": {
          "type": [
            "number",
            "null"
          ],
          "description": "raw (ungraded) price in US dollars; null when there is no price at that grade."
        },
        "psa10": {
          "type": [
            "number",
            "null"
          ],
          "description": "PSA 10 price in US dollars; null when there is no price at that grade."
        },
        "psa9": {
          "type": [
            "number",
            "null"
          ],
          "description": "PSA 9 price in US dollars; null when there is no price at that grade."
        },
        "psa8": {
          "type": [
            "number",
            "null"
          ],
          "description": "PSA 8 price in US dollars; null when there is no price at that grade."
        },
        "psa7": {
          "type": [
            "number",
            "null"
          ],
          "description": "PSA 7 price in US dollars; null when there is no price at that grade."
        },
        "bgs10": {
          "type": [
            "number",
            "null"
          ],
          "description": "BGS 9.5 (BGS 10 when there is no 9.5 price) price in US dollars; null when there is no price at that grade."
        },
        "cgc10": {
          "type": [
            "number",
            "null"
          ],
          "description": "CGC 10 price in US dollars; null when there is no price at that grade."
        },
        "sgc10": {
          "type": [
            "number",
            "null"
          ],
          "description": "SGC 10 price in US dollars; null when there is no price at that grade."
        }
      },
      "description": "Current prices by grade, in US dollars with two decimals. A grade with no price is null; `bgs10` holds the BGS 9.5 price."
    },
    "Prices": {
      "allOf": [
        {
          "$ref": "#/$defs/PriceGrid"
        },
        {
          "type": "object",
          "properties": {
            "volume": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Recent sales volume, a count."
            },
            "updated": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time",
              "description": "When this card's prices were last refreshed."
            },
            "fromSales": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "description": "Grades (keys of this object) whose price came from our own recent sold sales because no other price was on file for that grade."
            }
          }
        }
      ],
      "description": "The price block of GET /api/v1/prices/{cardId}: the grade grid plus volume and the last update."
    },
    "ScanCard": {
      "type": "object",
      "properties": {
        "id": {
          "type": [
            "integer",
            "null"
          ],
          "description": "The catalog id, or null when the match is not in our catalog yet."
        },
        "externalId": {
          "type": [
            "string",
            "null"
          ],
          "description": "Secondary id."
        },
        "name": {
          "type": [
            "string",
            "null"
          ],
          "description": "Card name; a parallel is named in brackets."
        },
        "playerName": {
          "type": [
            "string",
            "null"
          ],
          "description": "Player or character."
        },
        "year": {
          "type": [
            "integer",
            "string",
            "null"
          ]
        },
        "setName": {
          "type": [
            "string",
            "null"
          ],
          "description": "Set name."
        },
        "cardNumber": {
          "type": [
            "string",
            "null"
          ],
          "description": "Card number."
        },
        "printRun": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Print run for numbered cards."
        },
        "parallel": {
          "type": "string",
          "description": "The parallel, or `Base`."
        },
        "category": {
          "type": [
            "string",
            "null"
          ],
          "description": "Category."
        },
        "imageUrl": {
          "type": [
            "string",
            "null"
          ],
          "description": "Picture through our image link, or null.",
          "format": "uri"
        },
        "confidence": {
          "type": [
            "number",
            "null"
          ],
          "description": "0 to 1, three decimals."
        }
      }
    },
    "Slab": {
      "type": "object",
      "properties": {
        "grader": {
          "type": [
            "string",
            "null"
          ],
          "description": "PSA, BGS, CGC, SGC, TGA or null."
        },
        "grade": {
          "type": [
            "number",
            "string",
            "null"
          ],
          "description": "The numeric grade, `Authentic`, or null when unread."
        },
        "autoGrade": {
          "type": [
            "string",
            "null"
          ],
          "description": "Autograph grade when the label carries one."
        },
        "certNumber": {
          "type": [
            "string",
            "null"
          ],
          "description": "The cert number read from the label or the grader's record."
        },
        "certVerified": {
          "type": "boolean",
          "description": "true when the grader's record for that cert was found and agrees with the label."
        },
        "priceAtGrade": {
          "type": [
            "number",
            "null"
          ],
          "description": "The card's price at exactly this grade when we price that grade; null otherwise (never a neighbouring grade's price)."
        },
        "verifyUrl": {
          "type": [
            "string",
            "null"
          ],
          "description": "The grader's own page for the cert (PSA, CGC and TGA open the cert; Beckett and SGC open their lookup page).",
          "format": "uri"
        },
        "frontImageUrl": {
          "type": [
            "string",
            "null"
          ],
          "description": "The grader's front slab photo through our image link, when they have one.",
          "format": "uri"
        },
        "backImageUrl": {
          "type": [
            "string",
            "null"
          ],
          "description": "The grader's back slab photo through our image link, when they have one.",
          "format": "uri"
        }
      },
      "required": [
        "certVerified"
      ]
    }
  }
}