{"openapi":"3.0.3","info":{"title":"Towit API","version":"0.1.0","description":"Operational API for Towit vehicle transport intake, quotes, drivers, onboarding, and assignments."},"servers":[{"url":"https://api.towit.ai","description":"Current public IP"},{"url":"http://localhost:3000","description":"Local development"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Health"},{"name":"Customers"},{"name":"WhatsApp Intake"},{"name":"Jobs"},{"name":"Messages"},{"name":"Quotes"},{"name":"Drivers"},{"name":"Driver Onboarding"},{"name":"Assignments"}],"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health check","description":"Public health check for the API and database connection.","security":[],"responses":{"200":{"description":"API and database are available","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/customers":{"get":{"tags":["Customers"],"summary":"List customers","parameters":[{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Recent customers","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Customer"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Customers"],"summary":"Create or update customer","description":"Creates a customer, or updates an existing customer when phone_e164 already exists.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerInput"},"example":{"full_name":"Example Customer","phone_e164":"+447700900123","email":"customer@example.com","customer_type":"private","source_channel":"whatsapp","notes":"Prefers WhatsApp updates"}}}},"responses":{"201":{"description":"Customer created or updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/whatsapp/intake":{"post":{"tags":["WhatsApp Intake"],"summary":"Process inbound customer WhatsApp message","description":"Creates or updates the customer, active transport job, inbound message, outbound reply, and quote when distance can be calculated from supplied miles or pickup/delivery postcodes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppIntakeInput"},"example":{"from_phone_e164":"+447700900123","customer_name":"Example Customer","message_id":"wamid.example","body":"Hi, quote please. Reg AB12CDE, starts and drives, from B1 1AA to M1 1AE, open trailer, private customer.","customer_type":"private"}}}},"responses":{"201":{"description":"WhatsApp intake saved and reply generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhatsAppIntakeResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs":{"get":{"tags":["Jobs"],"summary":"List jobs","parameters":[{"$ref":"#/components/parameters/Limit"},{"name":"status","in":"query","schema":{"type":"string","example":"quote_needed"}}],"responses":{"200":{"description":"Recent jobs","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Jobs"],"summary":"Create job","description":"Creates a structured vehicle transport job. Existing IDs, nested objects, or a mix of both are accepted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobInput"},"example":{"customer":{"full_name":"Example Customer","phone_e164":"+447700900123","customer_type":"private"},"vehicle":{"registration":"AB12CDE","make":"BMW","model":"3 Series","condition_status":"starts_drives","has_keys":true},"pickup_location":{"postcode":"B1 1AA","town_city":"Birmingham"},"delivery_location":{"postcode":"M1 1AE","town_city":"Manchester"},"trailer_preference":"open","requested_by_channel":"whatsapp","source_message_id":"whatsapp-message-id"}}}},"responses":{"201":{"description":"Job created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs/{id}":{"get":{"tags":["Jobs"],"summary":"Get job","parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/jobs/{id}/status":{"patch":{"tags":["Jobs"],"summary":"Update job status","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateJobStatusInput"},"example":{"status":"quote_needed","actor_type":"openclaw","notes":"Pickup and delivery postcodes collected"}}}},"responses":{"200":{"description":"Job status updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/jobs/{id}/messages":{"post":{"tags":["Messages"],"summary":"Store job message","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageInput"},"example":{"channel":"whatsapp","external_message_id":"provider-message-id","direction":"inbound","sender_label":"Customer","body":"Pickup B1, delivery M1"}}}},"responses":{"201":{"description":"Message stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs/{id}/quotes":{"post":{"tags":["Quotes"],"summary":"Add quote","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteInput"},"example":{"status":"sent","transport_type":"open","distance_miles":120,"customer_price":264,"pricing_notes":"Private quote sent by operator"}}}},"responses":{"201":{"description":"Quote added","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/drivers":{"get":{"tags":["Drivers"],"summary":"List drivers","parameters":[{"$ref":"#/components/parameters/Limit"}],"responses":{"200":{"description":"Recent drivers","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Driver"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Drivers"],"summary":"Create driver","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverInput"},"example":{"full_name":"Driver Name","phone_e164":"+447700900555","email":"driver@example.com","company_name":"Driver Ltd","active":true,"transport_capability":["open"]}}}},"responses":{"201":{"description":"Driver created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/drivers/onboarding":{"get":{"tags":["Driver Onboarding"],"summary":"List driver onboarding queue","responses":{"200":{"description":"Driver onboarding queue","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/drivers/{id}/documents":{"post":{"tags":["Driver Onboarding"],"summary":"Add driver document","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverDocumentInput"},"example":{"document_type":"insurance","onboarding_stage":"stage_2","file_url":"https://storage.example.com/insurance.pdf","notes":"Expires June 2027"}}}},"responses":{"201":{"description":"Driver document stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/drivers/{id}/onboarding-status":{"patch":{"tags":["Driver Onboarding"],"summary":"Update driver onboarding status","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverOnboardingStatusInput"},"example":{"status":"towit_verified","reviewed_by":"Paul","notes":"Documents checked and approved"}}}},"responses":{"200":{"description":"Driver onboarding status updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DriverResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/jobs/{id}/assignments":{"post":{"tags":["Assignments"],"summary":"Assign job to driver","description":"Only active drivers with onboarding_status towit_verified can receive jobs.","parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignmentInput"},"example":{"driver_id":"00000000-0000-0000-0000-000000000000","status":"offered","notes":"Offer sent on WhatsApp"}}}},"responses":{"201":{"description":"Assignment created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Driver is not active and towit_verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Driver must be active and towit_verified before receiving jobs"}}}}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Use the current TOWIT_API_KEY value."}},"parameters":{"Id":{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},"Limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}},"responses":{"BadRequest":{"description":"Invalid request body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Unauthorized"}}}},"NotFound":{"description":"Record not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"HealthResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"database":{"type":"string","example":"connected"},"now":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"issues":{"type":"array","items":{"type":"object"}}}},"GenericDataResponse":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true}}},"GenericListResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"CustomerType":{"type":"string","enum":["unknown","private","dealer","leasing","garage","detailer","business","other"]},"VehicleCondition":{"type":"string","enum":["unknown","starts_drives","starts_not_driving","rolling","non_rolling","damaged"]},"TrailerPreference":{"type":"string","enum":["open","enclosed","no_preference"]},"CustomerInput":{"type":"object","properties":{"full_name":{"type":"string"},"phone_e164":{"type":"string"},"email":{"type":"string","format":"email"},"customer_type":{"$ref":"#/components/schemas/CustomerType"},"source_channel":{"type":"string","default":"whatsapp"},"notes":{"type":"string"}}},"Customer":{"allOf":[{"$ref":"#/components/schemas/CustomerInput"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}]},"CustomerResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Customer"}}},"WhatsAppIntakeInput":{"type":"object","required":["from_phone_e164","body"],"properties":{"from_phone_e164":{"type":"string","description":"Customer WhatsApp phone in E.164 format."},"customer_name":{"type":"string"},"message_id":{"type":"string"},"body":{"type":"string"},"customer_type":{"$ref":"#/components/schemas/CustomerType"},"pickup_postcode":{"type":"string"},"delivery_postcode":{"type":"string"},"vehicle_registration":{"type":"string"},"make":{"type":"string"},"model":{"type":"string"},"condition_status":{"$ref":"#/components/schemas/VehicleCondition"},"trailer_preference":{"$ref":"#/components/schemas/TrailerPreference"},"preferred_collection_at":{"type":"string","format":"date-time"},"distance_miles":{"type":"number","description":"Optional route distance. If omitted, the API estimates distance from pickup and delivery postcodes when possible."},"extracted":{"type":"object","additionalProperties":true,"description":"Optional structured extraction from OpenClaw or a WhatsApp provider."}}},"WhatsAppIntakeResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/Customer"},"job":{"$ref":"#/components/schemas/Job"},"quote":{"type":"object","nullable":true,"additionalProperties":true},"missing_details":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}}},"distance":{"type":"object","nullable":true,"additionalProperties":true},"reply":{"type":"string"},"outbound_message":{"type":"object","additionalProperties":true},"frontline_context":{"type":"object","additionalProperties":true}}}}},"VehicleInput":{"type":"object","properties":{"registration":{"type":"string"},"make":{"type":"string"},"model":{"type":"string"},"year":{"type":"integer"},"colour":{"type":"string"},"fuel_type":{"type":"string"},"tax_status":{"type":"string"},"mot_status":{"type":"string"},"mot_expiry_date":{"type":"string","format":"date"},"dvla_lookup_status":{"type":"string"},"dvla_checked_at":{"type":"string","format":"date-time"},"dvla_data":{"type":"object","additionalProperties":true},"condition_status":{"$ref":"#/components/schemas/VehicleCondition"},"has_keys":{"type":"boolean"},"damage_notes":{"type":"string"},"access_notes":{"type":"string"}}},"LocationInput":{"type":"object","properties":{"label":{"type":"string"},"postcode":{"type":"string"},"address_line1":{"type":"string"},"address_line2":{"type":"string"},"town_city":{"type":"string"},"county":{"type":"string"},"country":{"type":"string","default":"GB"},"contact_name":{"type":"string"},"contact_phone_e164":{"type":"string"},"access_notes":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"}}},"CreateJobInput":{"type":"object","properties":{"customer":{"$ref":"#/components/schemas/CustomerInput"},"customer_id":{"type":"string","format":"uuid"},"vehicle":{"$ref":"#/components/schemas/VehicleInput"},"vehicle_id":{"type":"string","format":"uuid"},"pickup_location":{"$ref":"#/components/schemas/LocationInput"},"pickup_location_id":{"type":"string","format":"uuid"},"delivery_location":{"$ref":"#/components/schemas/LocationInput"},"delivery_location_id":{"type":"string","format":"uuid"},"trailer_preference":{"$ref":"#/components/schemas/TrailerPreference"},"preferred_collection_at":{"type":"string","format":"date-time"},"collection_flexibility":{"type":"string"},"requested_by_channel":{"type":"string","default":"whatsapp"},"source_message_id":{"type":"string"},"operator_notes":{"type":"string"},"risk_flags":{"type":"array","items":{"type":"string"}}}},"Job":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","example":"intake"},"trailer_preference":{"$ref":"#/components/schemas/TrailerPreference"},"customer":{"$ref":"#/components/schemas/Customer"}}},"JobResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Job"}}},"UpdateJobStatusInput":{"type":"object","required":["status"],"properties":{"status":{"type":"string"},"actor_type":{"type":"string","enum":["system","customer","operator","driver","openclaw"],"default":"openclaw"},"actor_id":{"type":"string","format":"uuid"},"notes":{"type":"string"}}},"MessageInput":{"type":"object","required":["direction"],"properties":{"customer_id":{"type":"string","format":"uuid"},"channel":{"type":"string","default":"whatsapp"},"external_message_id":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"sender_label":{"type":"string"},"body":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"sent_at":{"type":"string","format":"date-time"}}},"QuoteInput":{"type":"object","properties":{"status":{"type":"string","enum":["draft","sent","accepted","rejected","expired","superseded"],"default":"draft"},"transport_type":{"type":"string","enum":["open","enclosed"],"default":"open"},"distance_miles":{"type":"number"},"driver_rate_per_mile":{"type":"number"},"margin_per_mile":{"type":"number"},"customer_rate_per_mile":{"type":"number"},"customer_price":{"type":"number"},"pricing_notes":{"type":"string"}}},"DriverInput":{"type":"object","required":["full_name"],"properties":{"full_name":{"type":"string"},"phone_e164":{"type":"string"},"email":{"type":"string","format":"email"},"company_name":{"type":"string"},"active":{"type":"boolean","default":true},"transport_capability":{"type":"array","items":{"type":"string"},"default":["open"]},"insurance_notes":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"}}},"Driver":{"allOf":[{"$ref":"#/components/schemas/DriverInput"},{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"onboarding_status":{"type":"string","enum":["stage_1_pending","stage_1_complete","stage_2_pending","stage_2_complete","towit_verified","rejected","suspended"]},"can_receive_jobs":{"type":"boolean"}}}]},"DriverResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Driver"}}},"DriverDocumentInput":{"type":"object","required":["document_type","file_url"],"properties":{"document_type":{"type":"string","enum":["driving_licence","insurance","trade_plate","identity","vehicle_photo","other"]},"onboarding_stage":{"type":"string","enum":["stage_1","stage_2"],"default":"stage_1"},"file_url":{"type":"string"},"notes":{"type":"string"}}},"DriverOnboardingStatusInput":{"type":"object","required":["status","reviewed_by"],"properties":{"status":{"type":"string","enum":["stage_1_pending","stage_1_complete","stage_2_pending","stage_2_complete","towit_verified","rejected","suspended"]},"reviewed_by":{"type":"string"},"notes":{"type":"string"}}},"AssignmentInput":{"type":"object","required":["driver_id"],"properties":{"driver_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["offered","accepted","declined","cancelled","completed"],"default":"offered"},"driver_pay":{"type":"number"},"notes":{"type":"string"}}}}}}