{"openapi":"3.1.0","info":{"title":"Trunkville API","version":"1.0.0","description":"The global directory of bespoke makers (tailors, shoemakers, shirtmakers) and their trunk shows. Makers confirm every appointment personally: agents may REQUEST an appointment on a client's behalf, never book one. The maker accepts, asks a question, suggests another time, or declines; the client is emailed at each step and gets a calendar invite on acceptance.","contact":{"email":"editor@trunkville.com","url":"https://trunkville.com"},"termsOfService":"https://www.trunkville.com/terms","x-privacy-policy":"https://www.trunkville.com/privacy"},"servers":[{"url":"https://trunkville.com"}],"externalDocs":{"description":"MCP server (Streamable HTTP, no sign-in) with the same tools: https://www.trunkville.com/api/mcp","url":"https://www.trunkville.com/llms.txt"},"x-mcp":{"url":"https://www.trunkville.com/api/mcp","transport":"streamable-http","auth":"none","tools":["search_makers","get_maker","list_trunk_shows","request_appointment","ask_maker","get_request"]},"paths":{"/api/makers":{"get":{"operationId":"searchMakers","summary":"Who comes to or near a place, makes a given thing, around a given price","description":"A place match (city or near) covers makers based there, coming there, and makers who visited in the last two years with nothing scheduled; each result carries `match` explaining which, so an assistant can offer to ask a past visitor to come again (POST /api/requests with city + preferred_times). Prices are compared in USD with rough fixed rates; makers without a listed starting price are excluded when a price filter is set.","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Free text: name, craft, or home city"},{"name":"near","in":"query","schema":{"type":"string"},"description":"Place name or 'lat,lng'; matches home, past and upcoming visits within radius_km"},{"name":"radius_km","in":"query","schema":{"type":"number","default":150,"maximum":1000}},{"name":"city","in":"query","schema":{"type":"string"},"description":"Exact city instead of a radius (home, past or upcoming)"},{"name":"visited","in":"query","schema":{"type":"string","enum":["any","upcoming","past"],"default":"any"}},{"name":"craft","in":"query","schema":{"type":"string"},"description":"e.g. shoes, suits, shirts"},{"name":"price_min","in":"query","schema":{"type":"number"},"description":"Starting price at least this, in `currency`"},{"name":"price_max","in":"query","schema":{"type":"number"},"description":"Starting price at most this, in `currency`"},{"name":"currency","in":"query","schema":{"type":"string","default":"USD"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"Makers with their next visit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MakerList"}}}}}}},"/api/makers/{slug}":{"get":{"operationId":"getMaker","summary":"A maker's profile, upcoming and past visits (with a city summary), and open appointment times","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Maker detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Maker"}}}},"404":{"description":"Not found"}}}},"/api/shows":{"get":{"operationId":"listTrunkShows","summary":"Trunk shows — upcoming by default; set `from` in the past to see where makers have been","parameters":[{"name":"city","in":"query","schema":{"type":"string"}},{"name":"country","in":"query","schema":{"type":"string"}},{"name":"near","in":"query","schema":{"type":"string"},"description":"Place name or 'lat,lng'"},{"name":"radius_km","in":"query","schema":{"type":"number","default":150}},{"name":"maker","in":"query","schema":{"type":"string"},"description":"Maker slug"},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Shows","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShowList"}}}}}}},"/api/requests":{"post":{"operationId":"requestAppointment","summary":"Ask a maker for an appointment, or send them a message (nothing is booked until they accept)","description":"Creates an appointment request, or with kind=message a plain message/question. If slot_id names one of the maker's open_times, that time is held for the maker to accept for up to 72 hours. Otherwise describe when suits in preferred_times. The maker may accept, ask a question (answer at thread_url or by email), suggest another time (the client confirms at confirm_url), or decline. A message holds nothing; the maker replies by email and can suggest a time. Identify your agent in `agent.name` — makers see it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRequestInput"}}}},"responses":{"201":{"description":"Request created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRequestCreated"}}}},"400":{"description":"Missing or invalid fields"},"404":{"description":"Maker not found"},"409":{"description":"That slot was just taken — pick another or omit slot_id"},"429":{"description":"This client already has three open requests with this maker"}}}},"/api/requests/{id}":{"get":{"operationId":"getAppointmentRequest","summary":"Status of an appointment request","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"The thread token from the creation response"}],"responses":{"200":{"description":"Status, messages, and any proposed or confirmed time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRequestStatus"}}}},"404":{"description":"Not found"}}}}},"components":{"schemas":{"MakerList":{"type":"object","properties":{"count":{"type":"integer"},"total":{"type":"integer"},"place":{"type":["object","null"],"properties":{"asked":{"type":"string"},"label":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"radius_km":{"type":"number"},"resolved_by":{"type":"string"}}},"price_filter":{"type":"object","properties":{"min":{"type":["number","null"]},"max":{"type":["number","null"]},"currency":{"type":"string"},"compared_in":{"type":"string"},"makers_without_listed_price_excluded":{"type":"integer"}}},"makers":{"type":"array","items":{"$ref":"#/components/schemas/MakerSummary"}},"how_to_book":{"type":"string"}}},"MakerSummary":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"based_in":{"type":["string","null"]},"crafts":{"type":"array","items":{"type":"string"}},"services":{"type":"array","items":{"type":"string"}},"starting_price":{"type":["string","null"]},"starting_price_usd_approx":{"type":["integer","null"]},"turnaround":{"type":["string","null"]},"next_visit":{"type":["object","null"],"properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"from":{"type":["string","null"],"format":"date"},"to":{"type":["string","null"],"format":"date"}}},"match":{"type":"object","description":"Present when city or near was given: why this maker matched","properties":{"summary":{"type":"string"},"home":{"type":["object","null"],"properties":{"city":{"type":["string","null"]},"km":{"type":["number","null"]}}},"upcoming":{"type":"array","items":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"from":{"type":["string","null"],"format":"date"},"to":{"type":["string","null"],"format":"date"},"km":{"type":["number","null"]}}}},"past":{"type":"array","items":{"type":"object","properties":{"city":{"type":["string","null"]},"country":{"type":["string","null"]},"times":{"type":"integer"},"last_visit":{"type":["string","null"],"format":"date"},"km":{"type":["number","null"]}}}},"nearest_km":{"type":["integer","null"]}}},"url":{"type":"string"},"api_url":{"type":"string"},"request_url":{"type":"string"}}},"Maker":{"allOf":[{"$ref":"#/components/schemas/MakerSummary"},{"type":"object","properties":{"website":{"type":["string","null"]},"bio":{"type":["string","null"]},"ateliers":{"type":"array","items":{"type":"object","properties":{"label":{"type":["string","null"]},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"maps_url":{"type":["string","null"]}}}},"upcoming_visits":{"type":"array","items":{"$ref":"#/components/schemas/Visit"}},"past_visits":{"type":"array","description":"Trunk shows in the last two years, newest first","items":{"$ref":"#/components/schemas/Visit"}},"cities":{"type":"array","description":"Cities the maker visits, most often first","items":{"type":"object","properties":{"city":{"type":"string"},"country":{"type":["string","null"]},"visits":{"type":"integer","description":"Past visits in the last two years"},"last_visit":{"type":["string","null"],"format":"date"},"next_visit":{"type":["string","null"],"format":"date"}}}},"open_times":{"type":"array","items":{"$ref":"#/components/schemas/OpenTime"}},"booking":{"type":"object","properties":{"policy":{"type":"string","enum":["request_only"]},"how":{"type":"string"},"request_page":{"type":"string"},"openapi":{"type":"string"}}}}}]},"Visit":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"venue":{"type":["string","null"]},"address":{"type":["string","null"]},"from":{"type":["string","null"],"format":"date"},"to":{"type":["string","null"],"format":"date"},"dates_tba":{"type":"boolean"},"hours":{"type":["string","null"],"description":"Opening hours as the maker wrote them"},"notes":{"type":["string","null"],"description":"The maker's notes for visitors: who is coming, how to book, access"}}},"OpenTime":{"type":"object","description":"starts_at/ends_at are the LOCAL wall time in the visit city, written with a Z suffix. Do not convert.","properties":{"slot_id":{"type":"string","format":"uuid"},"visit_id":{"type":["string","null"],"format":"uuid"},"starts_at":{"type":"string"},"ends_at":{"type":"string"},"timezone":{"type":"string"},"city":{"type":["string","null"]},"venue":{"type":["string","null"]},"note":{"type":["string","null"]},"maps_url":{"type":["string","null"]}}},"ShowList":{"type":"object","properties":{"count":{"type":"integer"},"shows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"maker":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"api_url":{"type":"string"}}},"city":{"type":["string","null"]},"country":{"type":["string","null"]},"venue":{"type":["string","null"]},"from":{"type":["string","null"],"format":"date"},"to":{"type":["string","null"],"format":"date"},"dates_tba":{"type":"boolean"},"hours":{"type":["string","null"]},"notes":{"type":["string","null"]},"request_url":{"type":"string"}}}}}},"AppointmentRequestInput":{"type":"object","required":["maker","name","email"],"properties":{"maker":{"type":"string","description":"Maker slug"},"kind":{"type":"string","enum":["appointment","message"],"default":"appointment","description":"appointment (needs commission; may hold a slot) or message (needs message; nothing held, no Accept)"},"name":{"type":"string","description":"The client's name"},"email":{"type":"string","format":"email","description":"The client's email — they receive the maker's answer and the calendar invite"},"phone":{"type":"string"},"commission":{"type":"string","description":"What the client would like to have made, e.g. 'a pair of black oxfords' (required for appointments)"},"first_bespoke":{"type":"boolean","description":"True if this would be the client's first bespoke commission"},"slot_id":{"type":"string","format":"uuid","description":"One of the maker's open_times — held while the maker decides"},"show_uuid":{"type":"string","format":"uuid","description":"The visit this is for, when no slot_id is given"},"city":{"type":"string","description":"Where the client would like to see the maker — use with preferred_times to ask for a visit to a city the maker has been to before (see the maker's past_visits / cities) but has no dates for yet"},"preferred_times":{"type":"string","description":"When suits, in words, when no slot_id is given"},"message":{"type":"string","description":"Anything else for the maker — introductions, context, questions (required for kind=message)"},"agent":{"type":"object","properties":{"name":{"type":"string"},"contact":{"type":"string"}},"description":"Identify the assistant making the request; makers see this"}}},"AppointmentRequestCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["appointment","message"]},"status":{"type":"string","enum":["pending"]},"awaiting":{"type":"string","enum":["maker"]},"maker":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"}}},"held_until":{"type":["string","null"],"format":"date-time"},"thread_url":{"type":"string","description":"Where the client can read and reply"},"thread_email":{"type":["string","null"],"description":"Reply-by-email address for this request, when enabled"},"status_url":{"type":"string"},"note":{"type":"string"}}},"AppointmentRequestStatus":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","accepted","declined","expired","withdrawn"]},"awaiting":{"type":["string","null"],"enum":["maker","client",null]},"maker":{"type":["object","null"],"properties":{"slug":{"type":"string"},"name":{"type":"string"}}},"requested":{"type":"object","properties":{"preferred_times":{"type":["string","null"]},"commission":{"type":["string","null"]},"message":{"type":["string","null"]}}},"appointment":{"$ref":"#/components/schemas/TimeDetail","description":"Present once accepted"},"proposed":{"$ref":"#/components/schemas/TimeDetail","description":"A time the maker suggested; confirm at confirm_url"},"confirm_url":{"type":"string"},"held":{"$ref":"#/components/schemas/TimeDetail"},"held_until":{"type":["string","null"]},"thread_url":{"type":"string"},"thread_email":{"type":["string","null"]},"messages":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string","enum":["maker","client"]},"via":{"type":"string"},"body":{"type":"string"},"at":{"type":"string"}}}},"created_at":{"type":"string"},"responded_at":{"type":["string","null"]}}},"TimeDetail":{"type":["object","null"],"properties":{"starts_at":{"type":"string"},"ends_at":{"type":"string"},"location":{"type":["string","null"]},"maps_url":{"type":["string","null"]},"note":{"type":["string","null"]},"timezone":{"type":"string"}}}}}}