{"openapi":"3.1.0","info":{"title":"AgentOpen Test Kitchen agent door","version":"0.1.0","description":"AgentOpen hosted door. Request-only booking, no live seat inventory, no authentication. The restaurant confirms by email or phone. A booking response is not a live seat confirmation."},"servers":[{"url":"https://agentopen.ai/r/agentopen-test-kitchen"}],"paths":{"/llms.txt":{"get":{"summary":"Machine-readable restaurant profile","responses":{"200":{"description":"Markdown profile"}}}},"/menu.md":{"get":{"summary":"Full menu with prices and allergens","responses":{"200":{"description":"Markdown menu"}}}},"/availability":{"get":{"summary":"Coarse opening windows (request-only, not live seats)","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"party","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":2}}],"responses":{"200":{"description":"Request-only availability payload"}}}},"/book":{"post":{"operationId":"requestTable","summary":"Request a table. The restaurant confirms by email or phone.","description":"Public. No authentication. Interprets date and time in the restaurant timezone and stores a requested booking. Does not confirm a seat.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["date","time","partySize","guestName","guestContact"],"properties":{"date":{"type":"string","format":"date","description":"Seating date, YYYY-MM-DD, in the restaurant timezone.","examples":["2026-12-01"]},"time":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$","description":"Seating time, HH:MM, in the restaurant timezone.","examples":["19:00"]},"partySize":{"type":"integer","minimum":1,"maximum":20,"description":"Further limited by the door profile party size min and max when those are published."},"guestName":{"type":"string","minLength":1},"guestContact":{"type":"object","properties":{"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":1}},"anyOf":[{"required":["email"]},{"required":["phone"]}],"description":"At least one of email or phone is required."},"idempotencyKey":{"type":"string","minLength":1,"description":"Optional. A repeat of the same key on this door returns the original booking."}}},"example":{"date":"2026-12-01","time":"19:00","partySize":2,"guestName":"Ada Lovelace","guestContact":{"email":"ada@example.com"},"idempotencyKey":"agent-req-1"}}}},"responses":{"200":{"description":"The idempotency key was already used. Returns the original booking.","content":{"application/json":{"schema":{"type":"object","required":["id","slug","status","date","time","partySize","message","cancelUrl"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"status":{"type":"string","description":"requested for a new booking. A repeated idempotency key returns the stored status.","examples":["requested"]},"date":{"type":"string","format":"date"},"time":{"type":"string","examples":["19:00"]},"partySize":{"type":"integer"},"message":{"type":"string"},"cancelUrl":{"type":"string"},"phone":{"type":"string","description":"Present only when the restaurant published a phone number."},"bookingUrl":{"type":"string","format":"uri","description":"Present only when the restaurant published an http(s) booking link."}}}}}},"201":{"description":"Booking request created","content":{"application/json":{"schema":{"type":"object","required":["id","slug","status","date","time","partySize","message","cancelUrl"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"status":{"type":"string","description":"requested for a new booking. A repeated idempotency key returns the stored status.","examples":["requested"]},"date":{"type":"string","format":"date"},"time":{"type":"string","examples":["19:00"]},"partySize":{"type":"integer"},"message":{"type":"string"},"cancelUrl":{"type":"string"},"phone":{"type":"string","description":"Present only when the restaurant published a phone number."},"bookingUrl":{"type":"string","format":"uri","description":"Present only when the restaurant published an http(s) booking link."}}},"example":{"id":"00000000-0000-4000-8000-000000000001","slug":"harbour","status":"requested","date":"2026-12-01","time":"19:00","partySize":2,"message":"The restaurant confirms by email or phone. This is not a live seat confirmation.","cancelUrl":"https://agentopen.ai/r/agentopen-test-kitchen/cancel","phone":"+47 21 00 00 00","bookingUrl":"https://book.example/harbour"}}}},"400":{"description":"Invalid body, party size outside the published policy, a date and time in the past, or a local time that does not exist in the restaurant timezone.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}},"404":{"description":"Restaurant not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}},"409":{"description":"Idempotency key is already in use on another door","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}}}}},"/cancel":{"post":{"operationId":"cancelBookingRequest","summary":"Cancel a booking request when the guest contact matches","description":"Public. No authentication. Requires the booking id and at least one of email or phone. Cancels only when every supplied contact matches the stored guest contact. The response does not include guest contact details.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":1}},"anyOf":[{"required":["id","email"]},{"required":["id","phone"]}],"description":"Booking id plus at least one of email or phone. The contact must match the booking."},"example":{"id":"00000000-0000-4000-8000-000000000001","email":"ada@example.com"}}}},"responses":{"200":{"description":"Booking request cancelled","content":{"application/json":{"schema":{"type":"object","required":["id","slug","status","message"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"status":{"type":"string","const":"cancelled"},"message":{"type":"string"}}},"example":{"id":"00000000-0000-4000-8000-000000000001","slug":"harbour","status":"cancelled","message":"The booking request is cancelled."}}}},"400":{"description":"Invalid body, or neither email nor phone was provided","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}},"403":{"description":"The contact does not match this booking. The body does not include the stored contact.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}},"404":{"description":"Restaurant or booking not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}}}}}},"components":{"schemas":{"BookingRequest":{"type":"object","required":["date","time","partySize","guestName","guestContact"],"properties":{"date":{"type":"string","format":"date","description":"Seating date, YYYY-MM-DD, in the restaurant timezone.","examples":["2026-12-01"]},"time":{"type":"string","pattern":"^(?:[01]\\d|2[0-3]):[0-5]\\d$","description":"Seating time, HH:MM, in the restaurant timezone.","examples":["19:00"]},"partySize":{"type":"integer","minimum":1,"maximum":20,"description":"Further limited by the door profile party size min and max when those are published."},"guestName":{"type":"string","minLength":1},"guestContact":{"type":"object","properties":{"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":1}},"anyOf":[{"required":["email"]},{"required":["phone"]}],"description":"At least one of email or phone is required."},"idempotencyKey":{"type":"string","minLength":1,"description":"Optional. A repeat of the same key on this door returns the original booking."}}},"BookingResponse":{"type":"object","required":["id","slug","status","date","time","partySize","message","cancelUrl"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"status":{"type":"string","description":"requested for a new booking. A repeated idempotency key returns the stored status.","examples":["requested"]},"date":{"type":"string","format":"date"},"time":{"type":"string","examples":["19:00"]},"partySize":{"type":"integer"},"message":{"type":"string"},"cancelUrl":{"type":"string"},"phone":{"type":"string","description":"Present only when the restaurant published a phone number."},"bookingUrl":{"type":"string","format":"uri","description":"Present only when the restaurant published an http(s) booking link."}}},"CancelRequest":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"phone":{"type":"string","minLength":1}},"anyOf":[{"required":["id","email"]},{"required":["id","phone"]}],"description":"Booking id plus at least one of email or phone. The contact must match the booking."},"CancelResponse":{"type":"object","required":["id","slug","status","message"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"status":{"type":"string","const":"cancelled"},"message":{"type":"string"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"details":{"type":"object"}}}}}}