{
  "openapi": "3.1.0",
  "info": {
    "title": "Mobile Diesel USA Booking API",
    "version": "1.0.0",
    "description": "Book mobile diesel repair for commercial trucks. Dispatch covers the Phoenix, AZ metro today; Chicago and Detroit are launching next and cannot be booked yet. Built for AI agents acting on behalf of fleets and operators. No estimates before diagnosis \u2014 the mechanic diagnoses on site, quotes, and the customer approves before work. No payment is collected via this API; dispatch confirms every booking with the driver by phone/SMS before assigning a mechanic. Every error includes a next_step field. Canonical URLs end with a trailing slash (e.g. /api/v1/services/); requests without one receive a 308 redirect that preserves method and body \u2014 follow it.",
    "contact": {
      "email": "help@mobiledieselusa.com",
      "url": "https://mobiledieselusa.com/for-agents/"
    }
  },
  "servers": [
    {
      "url": "https://mobiledieselusa.com/api/v1"
    }
  ],
  "paths": {
    "/services": {
      "get": {
        "operationId": "listServices",
        "summary": "Service catalog (all diagnose-first pricing)",
        "responses": {
          "200": {
            "description": "Catalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "services": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Service"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/coverage": {
      "get": {
        "operationId": "checkCoverage",
        "summary": "Check whether a location is covered",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "type": "number"
            },
            "description": "Latitude (preferred, with lng)"
          },
          {
            "name": "lng",
            "in": "query",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "city",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Alternative to lat/lng, e.g. \"Phoenix\""
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "State for a city lookup, e.g. \"AZ\". Needed for names that exist in several states (Glendale, Mesa, Peoria)."
          }
        ],
        "responses": {
          "200": {
            "description": "Coverage result: covered flag, matched market, launching_next when the location is in Chicago or Detroit, reason and next_step guidance"
          }
        },
        "description": "Only the Phoenix, AZ metro is covered today. Chicago, IL and Detroit, MI are launching next: they return covered=false with launching_next set. Other locations return covered=false. Always check coverage before booking and never promise dispatch."
      }
    },
    "/quote": {
      "post": {
        "operationId": "getPricingPolicy",
        "summary": "How pricing works for a service (no estimate before diagnosis)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "service_id"
                ],
                "properties": {
                  "service_id": {
                    "type": "string"
                  },
                  "urgency": {
                    "type": "string",
                    "enum": [
                      "emergency",
                      "same-day",
                      "next-day",
                      "scheduled"
                    ]
                  },
                  "location": {
                    "$ref": "#/components/schemas/Location"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pricing policy for the service: estimate_available=false, pricing.model=diagnose_first, pricing.steps[], payment_via_api=false, plus coverage when a location was given and next_step."
          },
          "400": {
            "description": "Invalid input; response lists valid_service_ids and next_step"
          }
        },
        "description": "There is no estimate before a mechanic diagnoses the truck. Returns the diagnose-first pricing policy for the service so the agent can explain it to the operator, then book. No numbers are returned."
      }
    },
    "/bookings": {
      "post": {
        "operationId": "createBooking",
        "summary": "Create a booking",
        "description": "Send an Idempotency-Key header to make retries safe. driver_phone must be reachable \u2014 dispatch confirms by phone/SMS before assigning a mechanic.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BookingRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Booking created: booking_id, status, track_url for the driver, status/cancel endpoints"
          },
          "400": {
            "description": "Invalid input; issues[] + next_step explain the fix"
          },
          "503": {
            "description": "Store unavailable; retry with same Idempotency-Key or call dispatch"
          }
        }
      }
    },
    "/bookings/{id}": {
      "get": {
        "operationId": "getBookingStatus",
        "summary": "Booking status",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "status: received | pending_sms_confirm | confirmed | dispatched | en_route | on_site | complete | cancelled | rejected, plus status_detail"
          },
          "404": {
            "description": "Unknown booking id"
          }
        }
      }
    },
    "/bookings/{id}/cancel": {
      "post": {
        "operationId": "cancelBooking",
        "summary": "Cancel a booking (before dispatch)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled"
          },
          "409": {
            "description": "Too late to cancel via API \u2014 call dispatch (next_step included)"
          },
          "404": {
            "description": "Unknown booking id"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Service": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "pricing": {
            "type": "string",
            "enum": [
              "diagnose_first"
            ],
            "description": "No estimate before diagnosis; the mechanic quotes on site and the customer approves before work."
          }
        }
      },
      "Location": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number"
          },
          "lng": {
            "type": "number"
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "notes": {
            "type": "string",
            "description": "e.g. \"Westbound shoulder near exit 143\""
          }
        }
      },
      "BookingRequest": {
        "type": "object",
        "required": [
          "service_id",
          "location",
          "driver_phone"
        ],
        "properties": {
          "service_id": {
            "type": "string",
            "description": "From GET /services"
          },
          "symptom": {
            "type": "string"
          },
          "urgency": {
            "type": "string",
            "enum": [
              "emergency",
              "same-day",
              "next-day",
              "scheduled"
            ]
          },
          "quote_id": {
            "type": "string"
          },
          "location": {
            "$ref": "#/components/schemas/Location"
          },
          "truck": {
            "type": "object",
            "properties": {
              "year": {},
              "make": {
                "type": "string"
              },
              "model": {
                "type": "string"
              },
              "engine": {
                "type": "string"
              },
              "vin_last8": {
                "type": "string"
              }
            }
          },
          "unit_number": {
            "type": "string"
          },
          "driver_name": {
            "type": "string"
          },
          "driver_phone": {
            "type": "string",
            "description": "REQUIRED. Reachable phone for the driver at the truck."
          },
          "contact_email": {
            "type": "string"
          },
          "fleet_company": {
            "type": "string"
          },
          "po_number": {
            "type": "string",
            "description": "Fleet PO for billing"
          }
        }
      }
    }
  }
}
