{
  "openapi": "3.1.0",
  "info": {
    "title": "DragGap Vehicle Comparisons and Public Data",
    "version": "2.0.0",
    "description": "Search published stock vehicle configurations, compare two exact IDs and cite the versioned DragGap HTML result. Results are simulated estimates, not instrumented tests. No authentication. The full catalogue directory is larger than the precomputed profile index: missing profiles return 404 and ambiguous names return 300 with choices. Use /api/v1/index for current coverage."
  },
  "servers": [{ "url": "https://draggap.com" }],
  "paths": {
    "/api/v1/index": {
      "get": {
        "operationId": "getComparisonIndex",
        "summary": "Get current result version, coverage and featured exact matchups",
        "responses": { "200": { "description": "Current version and coverage", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentIndex" } } } }, "503": { "$ref": "#/components/responses/AgentUnavailable" } }
      }
    },
    "/api/v1/vehicles": {
      "get": {
        "operationId": "searchRaceableProfiles",
        "summary": "Search published stock configurations by make, model, year and trim code",
        "description": "Inspect all choices and pick exact IDs. This endpoint searches published simulation profiles, not all catalogue records. Do not silently choose another year, body style or drivetrain when the requested trim is absent.",
        "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 }, "example": "2025 BMW i4 M50" },
          { "$ref": "#/components/parameters/Offset" }, { "$ref": "#/components/parameters/Limit" }, { "$ref": "#/components/parameters/Version" }
        ],
        "responses": { "200": { "description": "Exact configuration choices", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VehicleSearch" } } } }, "400": { "$ref": "#/components/responses/AgentError" }, "404": { "$ref": "#/components/responses/AgentError" }, "503": { "$ref": "#/components/responses/AgentUnavailable" } }
      }
    },
    "/api/v1/catalog": {
      "get": {
        "operationId": "searchVehicleFamilyDirectory",
        "summary": "Discover car and motorcycle families across the full catalogue",
        "description": "Identity directory only. A family here is not a promise of a published simulation profile. Use searchRaceableProfiles for exact comparable configurations.",
        "parameters": [{ "name": "q", "in": "query", "schema": { "type": "string", "maxLength": 120 } }, { "$ref": "#/components/parameters/Offset" }, { "$ref": "#/components/parameters/Limit" }, { "$ref": "#/components/parameters/Version" }],
        "responses": { "200": { "description": "Family names, year ranges and aliases", "content": { "application/json": { "schema": { "type": "object", "required": ["version", "families", "scope", "total"], "properties": { "version": { "type": "string" }, "scope": { "type": "string" }, "total": { "type": "integer" }, "families": { "type": "array", "items": { "type": "object", "properties": { "make": { "type": "string" }, "model": { "type": "string" }, "yearStart": { "type": ["integer", "null"] }, "yearEnd": { "type": ["integer", "null"] }, "aliases": { "type": "array", "items": { "type": "string" } }, "trimAliases": { "type": "array", "items": { "type": "string" } } } } }, "next": { "type": ["string", "null"] } } } } } }, "400": { "$ref": "#/components/responses/AgentError" }, "404": { "$ref": "#/components/responses/AgentError" } }
      }
    },
    "/api/v1/vehicles/{id}": {
      "get": {
        "operationId": "getVehicleSimulationProfile",
        "summary": "Get stock specs, provenance, conditions and baseline-lane simulated timings",
        "description": "Single profiles use the apex lane. Pair comparisons fix canonical ID order and use each lane's production throttle variation. Use compareStockVehicles for the exact pair result.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "maxLength": 114 } }, { "$ref": "#/components/parameters/Version" }],
        "responses": { "200": { "description": "Public vehicle profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SimulationProfile" } } } }, "400": { "$ref": "#/components/responses/AgentError" }, "404": { "$ref": "#/components/responses/AgentError" } }
      }
    },
    "/api/v1/compare": {
      "get": {
        "operationId": "compareStockVehicles",
        "summary": "Compare two exact stock configurations and obtain a citable result URL",
        "description": "Supply two distinct IDs from searchRaceableProfiles. An unambiguous textual query is accepted; multiple configurations return HTTP 300 with choices. No year/trim fallback, modifications or private race data. Reversing the IDs produces the same canonical result and lane order. Quarter-mile and 1 km winners are separate. Null gates mean not reached within the 1 km run, not impossible top speeds. Cite citation.url with the simulated-estimate qualification.",
        "parameters": [
          { "name": "a", "in": "query", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 160 }, "description": "First exact stock configuration ID." },
          { "name": "b", "in": "query", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 160 }, "description": "Second exact stock configuration ID." },
          { "$ref": "#/components/parameters/Version" }
        ],
        "responses": {
          "200": { "description": "Reproducible simulated comparison", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Comparison" } }, "text/markdown": { "schema": { "type": "string" } } } },
          "300": { "description": "Ambiguous name; choose an exact configuration from choices", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentError" } } } },
          "400": { "$ref": "#/components/responses/AgentError" }, "404": { "$ref": "#/components/responses/AgentError" }, "503": { "$ref": "#/components/responses/AgentUnavailable" }
        }
      }
    },
    "/data/vehicles/manifest.json": {
      "get": {
        "operationId": "getVehicleDataManifest",
        "summary": "Get source provenance and catalogue coverage",
        "description": "Returns build time, source URLs, licences and the number of official and supplemental records in the public catalogue.",
        "responses": {
          "200": { "description": "Vehicle data build manifest", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VehicleDataManifest" } } } },
          "404": { "description": "Manifest resource not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/data/vehicles/catalog.json": {
      "get": {
        "operationId": "getVehicleModelCatalog",
        "summary": "Get the searchable make and model catalogue",
        "description": "Returns a read-only index of makes and models. Use the shard paths in each entry to retrieve full configurations.",
        "responses": {
          "200": { "description": "Combined EPA and global supplemental model catalogue", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VehicleCatalog" } } } },
          "404": { "description": "Catalogue resource not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Version": { "name": "version", "in": "query", "description": "Release ID from /api/v1/index; omit for the current published index.", "schema": { "type": "string", "pattern": "^v1-[a-f0-9]{16}$" } },
      "Offset": { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } },
      "Limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 } }
    },
    "schemas": {
      "AgentIndex": { "type": "object", "required": ["version", "engineVersion", "generatedAt", "coverage", "resultType"], "properties": { "version": { "type": "string" }, "engineVersion": { "type": "string" }, "generatedAt": { "type": "string", "format": "date-time" }, "resultType": { "const": "simulation" }, "coverage": { "type": "object", "properties": { "indexedConfigurations": { "type": "integer" }, "possibleDistinctPairs": { "type": "integer" }, "catalogueFamilies": { "type": "integer" }, "scope": { "type": "string" } } }, "featuredPairs": { "type": "array", "items": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "type": "string" } } } } },
      "Vehicle": { "type": "object", "required": ["id", "year", "make", "model", "name", "trim", "drivetrain", "stock", "specs"], "properties": { "id": { "type": "string" }, "year": { "type": "integer" }, "make": { "type": "string" }, "model": { "type": "string" }, "name": { "type": "string" }, "trim": { "type": "string" }, "body": { "type": "string" }, "kind": { "type": "string" }, "drivetrain": { "type": "string" }, "transmission": { "type": "string" }, "powertrain": { "type": "string" }, "market": { "type": ["string", "null"] }, "stock": { "const": true }, "specs": { "type": "object", "properties": { "powerHp": { "type": ["number", "null"] }, "powerKw": { "type": ["number", "null"] }, "torqueNm": { "type": ["number", "null"] }, "massKg": { "type": ["number", "null"] } } } } },
      "VehicleSearch": { "type": "object", "required": ["version", "vehicles", "total", "scope"], "properties": { "version": { "type": "string" }, "query": { "type": "string" }, "total": { "type": "integer" }, "scope": { "type": "string" }, "offset": { "type": "integer" }, "limit": { "type": "integer" }, "vehicles": { "type": "array", "items": { "$ref": "#/components/schemas/Vehicle" } }, "next": { "type": ["string", "null"] } } },
      "NullableNumberMap": { "type": "object", "additionalProperties": { "type": ["number", "null"] }, "description": "Elapsed seconds or km/h as identified by the containing field; null means not reached before 1 km." },
      "SimulationProfile": { "type": "object", "required": ["vehicle", "provenance", "conditions", "results"], "properties": {
        "vehicle": { "$ref": "#/components/schemas/Vehicle" },
        "provenance": { "type": "object", "properties": { "provider": { "type": "string" }, "sourceLinks": { "type": "array", "items": { "type": "string", "format": "uri" } }, "sourceDeclaredExactFields": { "type": "array", "items": { "type": "string" } }, "supplementalFields": { "type": "array", "items": { "type": "string" } }, "estimatedFields": { "type": "array", "items": { "type": "string" } }, "note": { "type": "string" } } },
        "conditions": { "type": "object", "description": "Production stock setup, dry level standing start, lane variation phase, rider and load assumptions." },
        "results": { "type": "object", "properties": { "type": { "const": "simulation" }, "speedTimes": { "$ref": "#/components/schemas/NullableNumberMap" }, "distanceTimes": { "$ref": "#/components/schemas/NullableNumberMap" }, "trapSpeedsKmh": { "$ref": "#/components/schemas/NullableNumberMap" }, "rollingIntervals": { "$ref": "#/components/schemas/NullableNumberMap" }, "rollingIntervalBasis": { "type": "string" }, "stockTopSpeed": { "type": "object", "properties": { "referenceKmh": { "type": ["number", "null"] }, "estimateKmh": { "type": ["number", "null"] }, "enforcedCeilingKmh": { "type": ["number", "null"] }, "basis": { "type": ["string", "null"] }, "note": { "type": "string" } } }, "maxSpeedWithin1kmKmh": { "type": "number" }, "calibration": { "type": "object" }, "missingGateMeaning": { "type": "string" } } }
      } },
      "GateResult": { "type": "object", "required": ["distanceM", "winnerId", "tie", "elapsedSeconds", "trapSpeedKmh", "timeDifferenceSeconds", "gapAtWinnerFinishM"], "properties": { "distanceM": { "type": "number" }, "winnerId": { "type": ["string", "null"] }, "tie": { "type": "boolean", "description": "Times differ by less than 0.001 seconds." }, "elapsedSeconds": { "$ref": "#/components/schemas/NullableNumberMap" }, "trapSpeedKmh": { "$ref": "#/components/schemas/NullableNumberMap" }, "timeDifferenceSeconds": { "type": "number" }, "gapAtWinnerFinishM": { "type": "number", "description": "Physical longitudinal separation between timing reference points at the first gate crossing, not bumper clearance." }, "gapDefinition": { "type": "string" } } },
      "Comparison": { "type": "object", "required": ["version", "engineVersion", "resultType", "vehicles", "quarterMile", "oneKilometre", "citation", "links", "limitations"], "properties": { "version": { "type": "string" }, "engineVersion": { "type": "string" }, "generatedAt": { "type": "string", "format": "date-time" }, "resultType": { "const": "simulation" }, "stock": { "const": true }, "title": { "type": "string" }, "summary": { "type": "string" }, "vehicles": { "type": "array", "minItems": 2, "maxItems": 2, "items": { "$ref": "#/components/schemas/SimulationProfile" } }, "quarterMile": { "$ref": "#/components/schemas/GateResult" }, "oneKilometre": { "$ref": "#/components/schemas/GateResult" }, "splitWinners": { "type": "boolean" }, "citation": { "type": "object", "properties": { "publisher": { "const": "DragGap" }, "url": { "type": "string", "format": "uri" }, "label": { "type": "string" }, "date": { "type": "string" }, "requiredQualification": { "type": "string" } } }, "links": { "type": "object", "properties": { "html": { "type": "string", "format": "uri" }, "json": { "type": "string", "format": "uri" }, "markdown": { "type": "string", "format": "uri" }, "rerun": { "type": "string", "format": "uri" }, "methodology": { "type": "string", "format": "uri" } } }, "limitations": { "type": "array", "items": { "type": "string" } } } },
      "AgentError": { "type": "object", "required": ["error"], "properties": { "error": { "type": "string" }, "message": { "type": "string" }, "query": { "type": "string" }, "totalChoices": { "type": "integer" }, "choices": { "type": "array", "items": { "$ref": "#/components/schemas/Vehicle" } } } },
      "VehicleDataManifest": {
        "type": "object",
        "description": "Provenance and coverage metadata for the static vehicle dataset.",
        "required": ["generatedAt", "sources"],
        "properties": {
          "generatedAt": { "type": "string", "format": "date-time", "description": "UTC time when the static dataset was assembled." },
          "sources": { "type": "object", "additionalProperties": true, "description": "Source-specific record counts, URLs and licence notes." }
        },
        "additionalProperties": true
      },
      "VehicleCatalog": {
        "type": "object",
        "description": "Search index mapping vehicle makes and models to official EPA and open supplemental data shards.",
        "additionalProperties": true
      },
      "Error": {
        "type": "object",
        "description": "Machine-readable error returned when a public resource cannot be found.",
        "required": ["status", "message"],
        "properties": {
          "status": { "type": "integer", "example": 404 },
          "message": { "type": "string", "example": "Resource not found" }
        }
      }
    },
    "responses": {
      "AgentError": { "description": "Invalid input or exact configuration/version not indexed. Never substitute another trim.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentError" } } } },
      "AgentUnavailable": { "description": "The result index is temporarily unavailable; retry later.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentError" } } } },
      "NotFound": {
        "description": "The requested static data resource does not exist.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
