{
  "openapi": "3.0.3",
  "info": {
    "title": "TowAgent Partner API",
    "version": "1.0.0",
    "description": "Push impounds into TowAgent, read balances computed today, place and release holds, and record releases made outside the kiosk. Authenticate with an API key from Admin → Settings → Integrations. Outbound webhooks (signed with X-TowAgent-Signature, HMAC-SHA256 of `${timestamp}.${body}`) deliver vehicle.*, payment.*, hold.*, and call.ended events."
  },
  "servers": [{ "url": "https://towagent.io/api/v1" }],
  "security": [{ "apiKey": [] }],
  "components": {
    "securitySchemes": {
      "apiKey": { "type": "http", "scheme": "bearer", "description": "Bearer ta_live_<keyId>_<secret>. Scopes: vehicles:read, vehicles:write, holds:write, payments:read, locations:read." }
    },
    "schemas": {
      "Vehicle": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "licensePlate": { "type": "string" },
          "vin": { "type": "string", "nullable": true },
          "make": { "type": "string", "nullable": true },
          "model": { "type": "string", "nullable": true },
          "year": { "type": "integer", "nullable": true },
          "color": { "type": "string", "nullable": true },
          "status": { "type": "string", "enum": ["impounded", "pending_release", "released", "auction", "lien"] },
          "locationId": { "type": "string", "nullable": true },
          "lotLocation": { "type": "string", "nullable": true },
          "towDate": { "type": "string", "format": "date" },
          "towReason": { "type": "string", "nullable": true },
          "towFee": { "type": "number", "nullable": true },
          "dailyStorageRate": { "type": "number", "nullable": true },
          "additionalCharges": { "type": "number", "nullable": true },
          "amountDue": { "type": "number", "nullable": true, "description": "Intake snapshot. Use GET /vehicles/{id} for the balance computed today." },
          "activeHoldTypes": { "type": "array", "items": { "type": "string" } },
          "ownerName": { "type": "string", "nullable": true },
          "ownerPhone": { "type": "string", "nullable": true },
          "releaseDate": { "type": "string", "nullable": true },
          "releasedTo": { "type": "object", "nullable": true },
          "towCompanyReference": { "type": "string", "nullable": true },
          "createdAt": { "type": "string", "format": "date-time", "nullable": true },
          "updatedAt": { "type": "string", "format": "date-time", "nullable": true }
        }
      },
      "VehicleUpsert": {
        "type": "object",
        "required": ["licensePlate", "towDate"],
        "properties": {
          "licensePlate": { "type": "string" },
          "vin": { "type": "string" },
          "make": { "type": "string" },
          "model": { "type": "string" },
          "year": { "type": "integer" },
          "color": { "type": "string" },
          "status": { "type": "string", "enum": ["impounded", "pending_release", "auction", "lien"] },
          "locationId": { "type": "string", "nullable": true },
          "lotLocation": { "type": "string" },
          "towDate": { "type": "string", "format": "date" },
          "towReason": { "type": "string" },
          "towFee": { "type": "number" },
          "dailyStorageRate": { "type": "number" },
          "additionalCharges": { "type": "number" },
          "amountDue": { "type": "number" },
          "ownerName": { "type": "string" },
          "ownerPhone": { "type": "string" },
          "ownerEmail": { "type": "string" },
          "ownerAddress": { "type": "string" },
          "towCompanyReference": { "type": "string", "description": "Your invoice or call number; echoed back in webhooks." },
          "policeReportNumber": { "type": "string" },
          "notes": { "type": "string" }
        }
      },
      "Balance": {
        "type": "object",
        "properties": {
          "total": { "type": "number" },
          "storageDays": { "type": "integer" },
          "asOf": { "type": "string", "format": "date-time" },
          "lines": { "type": "array", "items": { "type": "object", "properties": { "label": { "type": "string" }, "amount": { "type": "number" } } } }
        }
      }
    }
  },
  "paths": {
    "/vehicles": {
      "get": {
        "summary": "List vehicles",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string" } },
          { "name": "locationId", "in": "query", "schema": { "type": "string" } },
          { "name": "plate", "in": "query", "schema": { "type": "string" } },
          { "name": "updatedSince", "in": "query", "schema": { "type": "string", "format": "date-time" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } },
          { "name": "cursor", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Vehicle" } }, "nextCursor": { "type": "string", "nullable": true } } } } } } }
      },
      "post": {
        "summary": "Create or update a vehicle by plate",
        "description": "Upsert within your organization by plate (open records only). Send an Idempotency-Key header to make retries safe.",
        "parameters": [{ "name": "Idempotency-Key", "in": "header", "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VehicleUpsert" } } } },
        "responses": { "200": { "description": "Updated" }, "201": { "description": "Created" } }
      }
    },
    "/vehicles/{id}": {
      "get": { "summary": "Get a vehicle with today's balance", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "allOf": [{ "$ref": "#/components/schemas/Vehicle" }, { "type": "object", "properties": { "balance": { "$ref": "#/components/schemas/Balance" } } }] } } } } } } } },
      "patch": { "summary": "Update vehicle facts", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VehicleUpsert" } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/vehicles/{id}/release": {
      "post": { "summary": "Record a release made outside TowAgent", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["releasedTo"], "properties": { "releaseDate": { "type": "string", "format": "date" }, "releasedTo": { "type": "object", "properties": { "name": { "type": "string" }, "relationship": { "type": "string", "enum": ["owner", "authorized", "insurance", "other"] } } }, "authorization": { "type": "string" } } } } } }, "responses": { "200": { "description": "Released" }, "409": { "description": "Already released or on hold" } } }
    },
    "/vehicles/{id}/holds": {
      "post": { "summary": "Place or release a hold", "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "oneOf": [{ "type": "object", "required": ["action", "type", "reason"], "properties": { "action": { "const": "place" }, "type": { "type": "string", "enum": ["police", "lien", "admin", "insurance", "investigative"] }, "reason": { "type": "string" }, "reference": { "type": "string" } } }, { "type": "object", "required": ["action"], "properties": { "action": { "const": "release" }, "holdId": { "type": "string" }, "type": { "type": "string" }, "note": { "type": "string" } } }] } } } }, "responses": { "200": { "description": "OK" } } }
    },
    "/locations": { "get": { "summary": "List your yards", "responses": { "200": { "description": "OK" } } } }
  },
  "x-webhooks": {
    "events": ["vehicle.created", "vehicle.updated", "vehicle.released", "payment.completed", "payment.refunded", "hold.placed", "hold.released", "call.ended"],
    "signature": "X-TowAgent-Signature: t=<unix seconds>,v1=<hex hmac sha256 of `${t}.${rawBody}` using your endpoint secret>. Reject if |now - t| > 300s.",
    "retries": "8 attempts over ~48 hours with exponential backoff. Return 2xx to acknowledge."
  }
}
