{
  "openapi": "3.1.1",
  "info": {
    "title": "TheYard API",
    "description": "A used-vehicle auction platform in .NET 10: a hundred thousand listings with server-derived auction windows, bidding against a simulated room, accounts, and two stores behind one set of ports. Every response is snake_case, every instant is milliseconds since the epoch, every amount is whole dollars, and every failure is an RFC 9457 problem. Built from commit 1d6b50b. The decisions behind the API are served beside it, under Decision Records.",
    "version": "1.0.3.161"
  },
  "servers": [
    {
      "url": "https://theyard.stevenstout.biz"
    }
  ],
  "paths": {
    "/api/vehicles": {
      "get": {
        "tags": [
          "Vehicles"
        ],
        "summary": "Search the catalogue",
        "description": "Every filter, the sort and the page are optional query parameters, applied on the server. The default page is the top hundred by auction time, live and ending soonest first. Each vehicle carries the server-derived auction facts, so a client formats and counts down and never re-implements the schedule.",
        "operationId": "ListVehicles",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Free text, matched against every filterable field and the derived auction status.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "make",
            "in": "query",
            "description": "One make, exactly as the facets list it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "body_style",
            "in": "query",
            "description": "One body style, exactly as the facets list it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "title_status",
            "in": "query",
            "description": "One title status, exactly as the facets list it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "province",
            "in": "query",
            "description": "One province, exactly as the facets list it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "live, upcoming or ended, on the server's clock. Anything else is a 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "ending-soonest (the default), price-asc, price-desc, condition or most-bids. Anything else is a 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size, 1 to 500; 100 when absent.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "How many matches to skip; 0 when absent.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "min_condition",
            "in": "query",
            "description": "The lowest condition grade to include.",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "price_min",
            "in": "query",
            "description": "The lowest standing price to include, in whole dollars.",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "price_max",
            "in": "query",
            "description": "The highest standing price to include, in whole dollars.",
            "schema": {
              "type": "number",
              "format": "double"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VehiclePage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/facets": {
      "get": {
        "tags": [
          "Vehicles"
        ],
        "summary": "The distinct values behind the filters",
        "description": "Makes, body styles, title statuses and provinces across the whole catalogue, for the dropdowns.",
        "operationId": "GetFacets",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InventoryFacets"
                }
              }
            }
          }
        }
      }
    },
    "/api/vehicles/{id}": {
      "get": {
        "tags": [
          "Vehicles"
        ],
        "summary": "One vehicle, with its auction facts",
        "operationId": "GetVehicle",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VehicleView"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/vehicles/{id}/bids": {
      "post": {
        "tags": [
          "Bids"
        ],
        "summary": "Bid on a vehicle",
        "description": "Whole dollars. The rules run on the server: a sold vehicle takes no bid, an amount at or above the buy-now price wins outright at that price, and anything else has to clear the minimum next bid measured against the room's standing price. A session bids on the store it was opened on.",
        "operationId": "PlaceBid",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BidRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BidResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          },
          {
            "SessionCookie": [ ]
          }
        ]
      }
    },
    "/api/vehicles/{id}/buy-now": {
      "post": {
        "tags": [
          "Bids"
        ],
        "summary": "Buy a vehicle outright",
        "description": "No body: the vehicle is named in the address. Refused when the vehicle has no buy-now price, is already sold, or its auction is not live.",
        "operationId": "BuyNow",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BidResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          },
          {
            "SessionCookie": [ ]
          }
        ]
      }
    },
    "/api/bids": {
      "get": {
        "tags": [
          "Bids"
        ],
        "summary": "The caller's standing on every vehicle they have bid on",
        "description": "Keyed by vehicle id. Signed out, this is an empty map rather than a 401: the page asks for it on every load, and no bids is the true answer for a visitor with no session.",
        "operationId": "GetMyBids",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "$ref": "#/components/schemas/BidView"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Bids"
        ],
        "summary": "Forget the caller's bids, and the room's answers to them",
        "description": "One person's start-over. Nobody else's bids move.",
        "operationId": "ResetMyBids",
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          },
          {
            "SessionCookie": [ ]
          }
        ]
      }
    },
    "/api/bids/history": {
      "get": {
        "tags": [
          "Bids"
        ],
        "summary": "The caller's bids, newest first, with the vehicle each is on",
        "operationId": "GetBidHistory",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BidHistory"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          },
          {
            "SessionCookie": [ ]
          }
        ]
      }
    },
    "/api/market/tick": {
      "post": {
        "tags": [
          "Bids"
        ],
        "summary": "One round of bidding by the room",
        "description": "The simulated room bids against the caller's auctions and a page of live ones, on the server's clock. Driven by the page rather than a timer, and only by a signed-in visitor, because moving the room moves everybody's prices.",
        "operationId": "TickRoom",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TickResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer": [ ]
          },
          {
            "SessionCookie": [ ]
          }
        ]
      }
    },
    "/api/docs/{slug}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "One of the served documents, as markdown with its code samples expanded",
        "description": "The slug is one the sidebar offers: readme, architecture, a record such as adr-openapi. Every live block is read from this build at request time.",
        "operationId": "GetDocument",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/docs/images/{name}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "A picture one of the served documents carries",
        "description": "The name is one a served document names, such as app-home.jpg or infrastructure.svg; the file is read from docs/images and nowhere else.",
        "operationId": "GetDocumentImage",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              },
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/docs/diagrams/{name}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "One diagram on its own page",
        "description": "The SVG inlined in a small HTML document, so it zooms with the browser and keeps its text selectable.",
        "operationId": "GetDiagram",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/docs/bicep": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "The infrastructure definition, as a markdown page",
        "operationId": "GetBicep",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/docs/resume": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "The author's resume",
        "operationId": "GetResume",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              }
            }
          }
        }
      }
    },
    "/resume": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "The resume, inline, at an address a link can carry",
        "description": "The same PDF as /api/docs/resume, opened in the browser under the author's name. An optional ?src= names the door the link was handed out through (linkedin, application, email, signature, post); it is counted and never stored, and any other value counts as other.",
        "operationId": "GetResumeAtItsAddress",
        "parameters": [
          {
            "name": "src",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "byte"
                }
              }
            }
          }
        }
      }
    },
    "/api/recommendations": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "The recommendations colleagues wrote on LinkedIn, in the order the site shows them",
        "description": "Every entry has the same seven fields: the writer's name and title, the address of their own LinkedIn page, how they worked with Steve, the month, the recommendation as paragraphs, and the one sentence a short place quotes. They come from one file, data/recommendations.json, the one place to add or adjust one; the gate holds the file to the shape and to the count the site states.",
        "operationId": "GetRecommendations",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecommendationsReply"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/version": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "The build this container was made from",
        "operationId": "GetVersion",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BuildInfo"
                }
              }
            }
          }
        }
      }
    },
    "/healthz": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Is the process up",
        "description": "The container's own health check. Answers ok the moment the process is listening and says nothing else.",
        "operationId": "Liveness",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/readyz": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Should traffic be sent here",
        "description": "The deploy's verify step. Only the checks that gate readiness run, and the database is not one of them: a container whose store is gone still serves the catalogue from files.",
        "operationId": "Readiness",
        "parameters": [
          {
            "name": "stores",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Every check, timed, and the build that answered",
        "description": "The Admin tab's health card. One check per store, named by the store, so a container running both says which one is unavailable.",
        "operationId": "GetHealth",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthReport"
                }
              }
            }
          }
        }
      }
    },
    "/api/pulse": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "How fast the site is answering, what it costs this month, and how long it has been up",
        "description": "The first screen's one reading, built from the same sources as the Admin tab's machines and cost cards and kept for fifteen seconds. Every figure is nullable; a null means unread, never zero.",
        "operationId": "GetPulse",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PulseReply"
                }
              }
            }
          }
        }
      }
    },
    "/api/errors": {
      "get": {
        "tags": [
          "Errors"
        ],
        "summary": "Recent server and browser errors, newest first",
        "description": "Two in-memory rings of fifty, merged. Exception types and stack frames, never messages: this list is public.",
        "operationId": "GetErrors",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ErrorEntry"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/errors/client": {
      "post": {
        "tags": [
          "Errors"
        ],
        "summary": "Report an error the browser caught",
        "description": "Anonymous by design, so a crash in the page reaches the same list a crash in the server does. The message and the stack are bounded and any address in them is masked before they are kept.",
        "operationId": "ReportBrowserError",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientErrorReport"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/stores": {
      "get": {
        "tags": [
          "Stores"
        ],
        "summary": "Which stores this container runs, and which one this request is on",
        "description": "A request names a store with the X-Yard-Store header (sql or cosmos) or gets the site's default. The other site, if there is one, is the same code with the other default.",
        "operationId": "GetStores",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoresView"
                }
              }
            }
          }
        }
      }
    },
    "/api/tests/summary": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "The gate's counts for this build, without the tests themselves",
        "description": "The landing page's evidence strip: the suites and their totals, read from the same file the Admin tab's tests card reads.",
        "operationId": "GetTestSummary",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestSummaryReport"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/register": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Create an account on this store and sign in",
        "description": "Answers the account and sets the session cookie. A few dozen registrations an hour are allowed across all strangers, and a refused password gives the slot back.",
        "operationId": "Register",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Credentials"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountView"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Sign in and receive the session cookie",
        "description": "One sentence for every way this can fail, including a locked account, so the reply never says which addresses are registered here. Five wrong passwords lock an account for five minutes.",
        "operationId": "Login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Credentials"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountView"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/forgot": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Email a reset link to an address",
        "description": "One sentence back whether or not the address has an account here, and one email per address per five minutes. A container with no sender configured says so.",
        "operationId": "ForgotPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetLinkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForgotReply"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/reset": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Use a reset link to choose a new password and sign in",
        "description": "The link works once, for an hour, on the site it was minted for. A refused password leaves the old one in place.",
        "operationId": "ResetPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountView"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": [
          "Accounts"
        ],
        "summary": "Sign out",
        "description": "Deletes the session cookie and answers the anonymous account. Never fails.",
        "operationId": "Logout",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountView"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "Accounts"
        ],
        "summary": "Who the session belongs to on this store",
        "description": "Signed out is an answer, not a 401: a session opened on the other store reads as signed out here.",
        "operationId": "WhoAmI",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountView"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AccountView": {
        "required": [
          "signed_in",
          "email",
          "member_since_ms"
        ],
        "type": "object",
        "properties": {
          "signed_in": {
            "type": "boolean",
            "description": "False for a visitor with no session on this store; the other two fields are null then."
          },
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "member_since_ms": {
            "type": [
              "null",
              "integer"
            ],
            "description": "When the account was created, in milliseconds since the epoch, UTC.",
            "format": "int64"
          }
        }
      },
      "BidHistory": {
        "required": [
          "count",
          "bids"
        ],
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "format": "int32"
          },
          "bids": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BidHistoryEntry"
            }
          }
        }
      },
      "BidHistoryEntry": {
        "required": [
          "vehicle_id",
          "title",
          "bid"
        ],
        "type": "object",
        "properties": {
          "vehicle_id": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "description": "Year, make and model, or (withdrawn) if the vehicle has left the catalogue."
          },
          "bid": {
            "$ref": "#/components/schemas/BidView"
          }
        }
      },
      "BidRequest": {
        "required": [
          "amount"
        ],
        "type": "object",
        "properties": {
          "amount": {
            "type": "integer",
            "description": "Whole dollars, at or above the vehicle's min_next_bid.",
            "format": "int32"
          }
        }
      },
      "BidResult": {
        "required": [
          "kind",
          "amount",
          "bid",
          "vehicle"
        ],
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "accepted, or won when the vehicle was bought outright, at the buy-now price or by a bid that reached it."
          },
          "amount": {
            "type": "integer",
            "description": "The amount the bid stands at, in whole dollars.",
            "format": "int32"
          },
          "bid": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The caller's standing on this vehicle after the bid, or null if a reset landed between the bid and this read.",
                "$ref": "#/components/schemas/BidView"
              }
            ]
          },
          "vehicle": {
            "$ref": "#/components/schemas/VehicleView"
          }
        }
      },
      "BidView": {
        "required": [
          "amount",
          "bid_count",
          "won_buy_now",
          "at_ms",
          "outbid",
          "market_amount",
          "highest_amount"
        ],
        "type": "object",
        "properties": {
          "amount": {
            "type": "integer",
            "format": "int32"
          },
          "bid_count": {
            "type": "integer",
            "format": "int32"
          },
          "won_buy_now": {
            "type": "boolean"
          },
          "at_ms": {
            "type": "integer",
            "format": "int64"
          },
          "outbid": {
            "type": "boolean"
          },
          "market_amount": {
            "type": [
              "null",
              "integer"
            ],
            "format": "int32"
          },
          "highest_amount": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "BuildInfo": {
        "required": [
          "version",
          "commit"
        ],
        "type": "object",
        "properties": {
          "version": {
            "type": "string",
            "description": "The changelog's top line when this build was made, or dev outside a build."
          },
          "commit": {
            "type": "string",
            "description": "The short commit, or local outside a build."
          }
        }
      },
      "ClientErrorReport": {
        "required": [
          "message",
          "stack",
          "path"
        ],
        "type": "object",
        "properties": {
          "message": {
            "type": [
              "null",
              "string"
            ],
            "description": "What the browser caught. Required; bounded and masked before it is kept."
          },
          "stack": {
            "type": [
              "null",
              "string"
            ],
            "description": "The stack, if there was one."
          },
          "path": {
            "type": [
              "null",
              "string"
            ],
            "description": "The page the visitor was on."
          }
        }
      },
      "Credentials": {
        "required": [
          "email",
          "password"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "null",
              "string"
            ],
            "description": "The address the account is under; one account per address on each store."
          },
          "password": {
            "type": [
              "null",
              "string"
            ],
            "description": "Eight characters or more; nothing else is required of it."
          }
        }
      },
      "ErrorEntry": {
        "required": [
          "at",
          "path",
          "status",
          "message",
          "frames"
        ],
        "type": "object",
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "path": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "format": "int32"
          },
          "message": {
            "type": "string"
          },
          "frames": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "ForgotReply": {
        "required": [
          "sent",
          "message"
        ],
        "type": "object",
        "properties": {
          "sent": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "HealthCheckEntry": {
        "required": [
          "name",
          "status",
          "detail",
          "duration_ms"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "duration_ms": {
            "type": "integer",
            "format": "int64"
          },
          "gates_readiness": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "HealthReport": {
        "required": [
          "status",
          "uptime_seconds",
          "version",
          "commit",
          "checks"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "healthy when every check passes, degraded otherwise."
          },
          "uptime_seconds": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "string"
          },
          "commit": {
            "type": "string"
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HealthCheckEntry"
            }
          },
          "kept_warm": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "description": "The keep-warm loop's last pass (ADR: Kept awake); null where the loop is off.",
                "$ref": "#/components/schemas/KeepWarmReading"
              }
            ]
          }
        }
      },
      "InventoryFacets": {
        "required": [
          "makes",
          "body_styles",
          "title_statuses",
          "provinces"
        ],
        "type": "object",
        "properties": {
          "makes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "body_styles": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "title_statuses": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "provinces": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "KeepWarmReading": {
        "required": [
          "last_pass",
          "reads",
          "failed",
          "slowest_ms",
          "slowest"
        ],
        "type": "object",
        "properties": {
          "last_pass": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "reads": {
            "type": "integer",
            "format": "int32"
          },
          "failed": {
            "type": "integer",
            "format": "int32"
          },
          "slowest_ms": {
            "type": "integer",
            "format": "int64"
          },
          "slowest": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "type": [
              "null",
              "integer"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "PulseReply": {
        "required": [
          "usual_p95_ms_24h",
          "requests_24h",
          "month_to_date",
          "forecast_month",
          "currency",
          "cost_read_at_ms",
          "uptime_seconds",
          "version",
          "commit",
          "read_at_ms"
        ],
        "type": "object",
        "properties": {
          "usual_p95_ms_24h": {
            "type": [
              "null",
              "integer"
            ],
            "format": "int64"
          },
          "requests_24h": {
            "type": [
              "null",
              "integer"
            ],
            "format": "int32"
          },
          "month_to_date": {
            "type": [
              "null",
              "number"
            ],
            "format": "double"
          },
          "forecast_month": {
            "type": [
              "null",
              "number"
            ],
            "format": "double"
          },
          "currency": {
            "type": "string"
          },
          "cost_read_at_ms": {
            "type": [
              "null",
              "integer"
            ],
            "format": "int64"
          },
          "uptime_seconds": {
            "type": "integer",
            "format": "int64"
          },
          "version": {
            "type": "string"
          },
          "commit": {
            "type": "string"
          },
          "read_at_ms": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "Recommendation": {
        "required": [
          "name",
          "title",
          "profile",
          "relationship",
          "when",
          "paragraphs",
          "pull"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "profile": {
            "type": "string"
          },
          "relationship": {
            "type": "string"
          },
          "when": {
            "type": "string"
          },
          "paragraphs": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "pull": {
            "type": "string"
          }
        }
      },
      "RecommendationsReply": {
        "required": [
          "source",
          "recommendations"
        ],
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "recommendations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Recommendation"
            }
          }
        }
      },
      "ResetLinkRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ResetRequest": {
        "required": [
          "token",
          "password"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": [
              "null",
              "string"
            ],
            "description": "The GUID from the reset link; it works once, for an hour."
          },
          "password": {
            "type": [
              "null",
              "string"
            ],
            "description": "The new password, eight characters or more."
          }
        }
      },
      "StoresView": {
        "required": [
          "current",
          "stores",
          "other_site"
        ],
        "type": "object",
        "properties": {
          "current": {
            "type": "string"
          },
          "stores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StoreView"
            }
          },
          "other_site": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "StoreView": {
        "required": [
          "key",
          "name",
          "ready",
          "default"
        ],
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "ready": {
            "type": "boolean"
          },
          "default": {
            "type": "boolean"
          }
        }
      },
      "TestSuiteCount": {
        "required": [
          "id",
          "name",
          "passed",
          "failed",
          "skipped",
          "seconds",
          "carried"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "passed": {
            "type": "integer",
            "format": "int32"
          },
          "failed": {
            "type": "integer",
            "format": "int32"
          },
          "skipped": {
            "type": "integer",
            "format": "int32"
          },
          "seconds": {
            "type": "integer",
            "format": "int32"
          },
          "carried": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "TestSummaryReport": {
        "required": [
          "version",
          "ran_at",
          "gate_seconds",
          "passed",
          "failed",
          "skipped",
          "suites"
        ],
        "type": "object",
        "properties": {
          "version": {
            "type": "string"
          },
          "ran_at": {
            "type": "string"
          },
          "gate_seconds": {
            "type": "integer",
            "format": "int32"
          },
          "passed": {
            "type": "integer",
            "format": "int32"
          },
          "failed": {
            "type": "integer",
            "format": "int32"
          },
          "skipped": {
            "type": "integer",
            "format": "int32"
          },
          "suites": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestSuiteCount"
            }
          }
        }
      },
      "TickResult": {
        "required": [
          "raised",
          "bids"
        ],
        "type": "object",
        "properties": {
          "raised": {
            "type": "integer",
            "description": "How many auctions the room raised this round.",
            "format": "int32"
          },
          "bids": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/BidView"
            },
            "description": "The caller's standing on every vehicle they have bid on, keyed by vehicle id."
          }
        }
      },
      "VehiclePage": {
        "required": [
          "total",
          "vehicles"
        ],
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "How many vehicles match the whole query, not how many are on this page.",
            "format": "int32"
          },
          "vehicles": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VehicleView"
            }
          }
        }
      },
      "VehicleView": {
        "required": [
          "id",
          "vin",
          "year",
          "make",
          "model",
          "trim",
          "body_style",
          "exterior_color",
          "interior_color",
          "engine",
          "transmission",
          "drivetrain",
          "odometer_km",
          "fuel_type",
          "condition_grade",
          "condition_report",
          "damage_notes",
          "title_status",
          "province",
          "city",
          "auction_start",
          "starting_bid",
          "buy_now_price",
          "images",
          "selling_dealership",
          "lot",
          "current_bid",
          "bid_count",
          "auction_starts_at",
          "auction_ends_at",
          "auction_status",
          "min_next_bid",
          "reserve_state",
          "sold"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "vin": {
            "type": "string"
          },
          "year": {
            "type": "integer",
            "format": "int32"
          },
          "make": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "trim": {
            "type": "string"
          },
          "body_style": {
            "type": "string"
          },
          "exterior_color": {
            "type": "string"
          },
          "interior_color": {
            "type": "string"
          },
          "engine": {
            "type": "string"
          },
          "transmission": {
            "type": "string"
          },
          "drivetrain": {
            "type": "string"
          },
          "odometer_km": {
            "type": "integer",
            "format": "int32"
          },
          "fuel_type": {
            "type": "string"
          },
          "condition_grade": {
            "type": "number",
            "format": "double"
          },
          "condition_report": {
            "type": "string"
          },
          "damage_notes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "title_status": {
            "type": "string"
          },
          "province": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "auction_start": {
            "type": "string",
            "description": "The dataset's own date string, passed through; nothing is derived from it."
          },
          "starting_bid": {
            "type": "integer",
            "format": "int32"
          },
          "buy_now_price": {
            "type": [
              "null",
              "integer"
            ],
            "description": "null means no buy-now option.",
            "format": "int32"
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Gallery paths under /api/images, chosen for the body style."
          },
          "selling_dealership": {
            "type": "string"
          },
          "lot": {
            "type": "string"
          },
          "current_bid": {
            "type": [
              "null",
              "integer"
            ],
            "description": "The standing price, or null until the first bid.",
            "format": "int32"
          },
          "bid_count": {
            "type": "integer",
            "format": "int32"
          },
          "auction_starts_at": {
            "type": "integer",
            "description": "When the auction opens, in milliseconds since the epoch, UTC. Derived from the id on the server's clock.",
            "format": "int64"
          },
          "auction_ends_at": {
            "type": "integer",
            "description": "When the auction closes, in milliseconds since the epoch, UTC.",
            "format": "int64"
          },
          "auction_status": {
            "type": "string",
            "description": "live, upcoming or ended, on the server's clock at the moment of the response."
          },
          "min_next_bid": {
            "type": "integer",
            "description": "The smallest bid the rules will accept next, in whole dollars.",
            "format": "int32"
          },
          "reserve_state": {
            "type": "string",
            "description": "no-reserve, met or not-met: whether the standing bid has reached the seller's reserve. The reserve amount is never sent."
          },
          "sold": {
            "type": "boolean",
            "description": "True once anybody has bought the vehicle outright; a sold vehicle takes no more bids from anyone."
          }
        }
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "http",
        "description": "The session token, issued by register, login and reset, sent as a bearer header.",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "SessionCookie": {
        "type": "apiKey",
        "description": "The same token as the browser carries it: an httpOnly cookie set by register, login and reset.",
        "name": "theyard_session",
        "in": "cookie"
      }
    }
  },
  "tags": [
    {
      "name": "Vehicles"
    },
    {
      "name": "Bids"
    },
    {
      "name": "Documents"
    },
    {
      "name": "Health"
    },
    {
      "name": "Errors"
    },
    {
      "name": "Stores"
    },
    {
      "name": "Admin"
    },
    {
      "name": "Accounts"
    }
  ]
}