{
  "openapi": "3.1.0",
  "info": {
    "title": "Battery Figures agent lookup",
    "version": "1.0.0",
    "summary": "Free preview of a used Tesla by VIN, with the link to buy Tesla's own battery figure.",
    "description": "For AI assistants. Give an assistant a Tesla VIN and it gets the pack, the original capacity, the capacity a car of that model and age normally still holds, what that does not say about this exact car, the price and the link that buys Tesla's own figure. No account, no key, no Tesla call, never any count."
  },
  "servers": [
    {
      "url": "https://batteryfigures.com"
    }
  ],
  "security": [],
  "paths": {
    "/check/{vin}.json": {
      "get": {
        "operationId": "previewVinJson",
        "summary": "Free preview of a Tesla by VIN (always JSON)",
        "description": "What the VIN and the reference data say for free: the battery pack and its original capacity, the capacity a car of this model and age normally still holds (the typical range), what that range does not cover (gap), and the link that buys Tesla's own battery figure for this exact car (next.url). Calls no Tesla service. Never indexed. Always JSON, whatever the Accept header or User-Agent. HEAD answers the same headers without a body.",
        "parameters": [
          {
            "name": "vin",
            "in": "path",
            "required": true,
            "description": "The 17-character VIN of a Tesla Model S, 3, X or Y, in capitals (lower case is redirected, 301, to capitals).",
            "schema": {
              "type": "string",
              "pattern": "^[A-HJ-NPR-Z0-9]{17}$"
            },
            "example": "5YJ3E1EA2MF123456"
          }
        ],
        "responses": {
          "200": {
            "description": "The free preview: what is normal for this model at this age, never this car's condition.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Preview"
                }
              }
            }
          },
          "400": {
            "description": "The path is not a VIN (status invalid_vin).",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "404": {
            "description": "The VIN was not made by Tesla (not_tesla) or is a Tesla this site does not cover (unsupported_model).",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "429": {
            "description": "More than 60 requests a minute from one address. Wait for Retry-After seconds.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimited"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable (status unavailable). Try again in a minute.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "301": {
            "description": "The VIN was written in lower case: repeat the request at the Location, which carries it in capitals.",
            "headers": {
              "Location": {
                "description": "The same path with the VIN in capitals.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            }
          }
        }
      }
    },
    "/check/{vin}": {
      "get": {
        "operationId": "previewVin",
        "summary": "The same preview; send Accept: application/json",
        "description": "Answers exactly as /check/{vin}.json, with one difference: a person in a browser (an Accept header that prefers text/html and a browser User-Agent) gets a 302 into the Battery Figures app with the VIN filled in. Agents and scripts get the JSON. Prefer /check/{vin}.json, which never redirects. The answers vary with Accept and User-Agent.",
        "parameters": [
          {
            "name": "vin",
            "in": "path",
            "required": true,
            "description": "The 17-character VIN of a Tesla Model S, 3, X or Y, in capitals (lower case is redirected, 301, to capitals).",
            "schema": {
              "type": "string",
              "pattern": "^[A-HJ-NPR-Z0-9]{17}$"
            },
            "example": "5YJ3E1EA2MF123456"
          }
        ],
        "responses": {
          "200": {
            "description": "The free preview: what is normal for this model at this age, never this car's condition.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Preview"
                }
              }
            }
          },
          "400": {
            "description": "The path is not a VIN (status invalid_vin).",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "404": {
            "description": "The VIN was not made by Tesla (not_tesla) or is a Tesla this site does not cover (unsupported_model).",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "429": {
            "description": "More than 60 requests a minute from one address. Wait for Retry-After seconds.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimited"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable (status unavailable). Try again in a minute.",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreviewError"
                }
              }
            }
          },
          "301": {
            "description": "The VIN was written in lower case: repeat the request at the Location, which carries it in capitals.",
            "headers": {
              "Location": {
                "description": "The same path with the VIN in capitals.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            }
          },
          "302": {
            "description": "Only for a browser: the person is sent into the app (https://batteryfigures.com/?utm_source=check#/check?vin=<VIN>), or to the home page when the path is not a VIN. No body.",
            "headers": {
              "Location": {
                "description": "The app URL with the VIN, the same as next.url.",
                "schema": {
                  "type": "string"
                }
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/NoStore"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            }
          }
        }
      }
    },
    "/check/{a}/{b}": {
      "get": {
        "operationId": "previewNotFound",
        "summary": "Any deeper path under /check/",
        "description": "Not a lookup. Agents get 404 with status not_found; browsers are sent to the home page (302).",
        "parameters": [
          {
            "name": "a",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "b",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "404": {
            "description": "No such path (status not_found).",
            "headers": {
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              },
              "Access-Control-Allow-Origin": {
                "$ref": "#/components/headers/AccessControlAllowOrigin"
              },
              "Vary": {
                "$ref": "#/components/headers/Vary"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotFound"
                }
              }
            }
          },
          "302": {
            "description": "Only for a browser: sent to the home page.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              },
              "X-Robots-Tag": {
                "$ref": "#/components/headers/XRobotsTag"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Preview": {
        "type": "object",
        "properties": {
          "vin": {
            "type": "string",
            "description": "The VIN, in capitals.",
            "pattern": "^[A-HJ-NPR-Z0-9]{17}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok"
            ]
          },
          "car": {
            "type": "object",
            "properties": {
              "model": {
                "type": "string",
                "description": "Model S, Model 3, Model X or Model Y."
              },
              "modelYear": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "From VIN position 10; null when the VIN gives none."
              },
              "factory": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The plant, from VIN position 11."
              },
              "checkDigit": {
                "type": "string",
                "enum": [
                  "valid",
                  "invalid"
                ],
                "description": "invalid means the VIN has a typo; the preview is still given."
              }
            },
            "required": [
              "model",
              "modelYear",
              "factory",
              "checkDigit"
            ],
            "additionalProperties": false
          },
          "battery": {
            "type": "object",
            "properties": {
              "match": {
                "type": "string",
                "enum": [
                  "one",
                  "several",
                  "none"
                ],
                "description": "How many packs fit this VIN: one, several (the VIN alone cannot tell which) or none."
              },
              "packs": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Pack"
                }
              }
            },
            "required": [
              "match",
              "packs"
            ],
            "additionalProperties": false
          },
          "typical": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "ageYears": {
                "type": "number",
                "description": "The car's age in years."
              },
              "low": {
                "type": "number",
                "description": "Capacity left, % of original, at the low end of the typical range."
              },
              "high": {
                "type": "number",
                "description": "Capacity left, % of original, at the high end of the typical range."
              },
              "basis": {
                "type": "string",
                "enum": [
                  "capacity_left_percent"
                ]
              },
              "source": {
                "type": "string",
                "enum": [
                  "battery_figures",
                  "public_study"
                ]
              },
              "sourceName": {
                "type": "string",
                "description": "Where the range comes from, in words."
              }
            },
            "required": [
              "ageYears",
              "low",
              "high",
              "basis",
              "source",
              "sourceName"
            ],
            "additionalProperties": false,
            "description": "What is normal for this model at this age. null when the VIN gives no model year. Never this car's own condition."
          },
          "gap": {
            "type": "object",
            "properties": {
              "typicalCovers": {
                "type": "string",
                "enum": [
                  "model_at_age",
                  "none"
                ],
                "description": "model_at_age: the typical range is for the model at this age. none: there is no range."
              },
              "thisCar": {
                "type": "string",
                "enum": [
                  "needs_lookup"
                ],
                "description": "This exact car's battery figure comes from Tesla and needs a lookup."
              },
              "text": {
                "type": "string",
                "description": "The same, in one sentence to pass on."
              }
            },
            "required": [
              "typicalCovers",
              "thisCar",
              "text"
            ],
            "additionalProperties": false,
            "description": "What the free answer does not cover."
          },
          "next": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "enum": [
                  "buy_lookup"
                ]
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Give this link to the user: it opens the app with the VIN filled in."
              },
              "price": {
                "type": "string",
                "description": "The cheapest way in, in words."
              },
              "pricingUrl": {
                "type": "string",
                "format": "uri"
              },
              "gives": {
                "type": "string",
                "description": "What a lookup gives the buyer."
              }
            },
            "required": [
              "action",
              "url",
              "price",
              "pricingUrl",
              "gives"
            ],
            "additionalProperties": false
          },
          "notice": {
            "type": "string",
            "description": "What this preview is, in one sentence; begins with a warning when the check digit is wrong."
          },
          "agent": {
            "type": "object",
            "properties": {
              "instruction": {
                "type": "string",
                "description": "How to present the answer to the user."
              }
            },
            "required": [
              "instruction"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "vin",
          "status",
          "car",
          "battery",
          "typical",
          "gap",
          "next",
          "notice",
          "agent"
        ],
        "additionalProperties": false,
        "description": "The free preview of one Tesla VIN."
      },
      "Pack": {
        "type": "object",
        "properties": {
          "generation": {
            "type": "string",
            "description": "The pack generation."
          },
          "variant": {
            "type": "string",
            "description": "The pack variant."
          },
          "chemistry": {
            "type": "string",
            "description": "Cell chemistry, e.g. NCA, NMC or LFP."
          },
          "cellMaker": {
            "type": "string",
            "description": "Who makes the cells."
          },
          "originalKwh": {
            "type": [
              "number",
              "null"
            ],
            "description": "Original capacity in kWh; null when it is not known for this pack."
          }
        },
        "required": [
          "generation",
          "variant",
          "chemistry",
          "cellMaker",
          "originalKwh"
        ],
        "additionalProperties": false
      },
      "PreviewError": {
        "type": "object",
        "properties": {
          "vin": {
            "type": "string",
            "description": "The VIN as sent, in capitals when it is a VIN. Empty when the status is unavailable (503)."
          },
          "status": {
            "type": "string",
            "enum": [
              "invalid_vin",
              "not_tesla",
              "unsupported_model",
              "unavailable"
            ]
          },
          "message": {
            "type": "string",
            "description": "What went wrong, in one sentence."
          }
        },
        "required": [
          "vin",
          "status",
          "message"
        ],
        "additionalProperties": false
      },
      "RateLimited": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "rate_limited"
            ]
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      },
      "NotFound": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "not_found"
            ]
          }
        },
        "required": [
          "status"
        ],
        "additionalProperties": false
      }
    },
    "headers": {
      "XRobotsTag": {
        "description": "noindex: the answer is never indexed.",
        "schema": {
          "type": "string",
          "enum": [
            "noindex"
          ]
        }
      },
      "CacheControl": {
        "description": "public, max-age=3600 for 200, 400 and 404.",
        "schema": {
          "type": "string",
          "examples": [
            "public, max-age=3600"
          ]
        }
      },
      "NoStore": {
        "description": "no-store.",
        "schema": {
          "type": "string",
          "enum": [
            "no-store"
          ]
        }
      },
      "AccessControlAllowOrigin": {
        "description": "* : any origin may read the answer.",
        "schema": {
          "type": "string",
          "enum": [
            "*"
          ]
        }
      },
      "Vary": {
        "description": "Accept, User-Agent: the same URL answers JSON or a redirect. Not sent on /check/{vin}.json.",
        "schema": {
          "type": "string",
          "enum": [
            "Accept, User-Agent"
          ]
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait: 60.",
        "schema": {
          "type": "string",
          "enum": [
            "60"
          ]
        }
      }
    }
  },
  "x-mcp": {
    "url": "https://api.batteryfigures.com/mcp",
    "transport": "streamable-http",
    "auth": "none",
    "tools": [
      "preview_vin"
    ],
    "description": "The same free preview as /check/{vin}.json as one MCP tool, preview_vin(vin). POST only, stateless, JSON responses, the same rate limit as /check. A browser page of another origin is refused (403); agent clients send no Origin."
  }
}
