{"openapi":"3.1.0","info":{"title":"NOGLUTEATALY Agent Booking API","version":"1.0.0","summary":"Discover Rome gluten-free tours and create Stripe Checkout bookings.","description":"Public JSON API for AI agents and integrations. NOGLUTEATALY is a Rome food-tour and cooking-class company, not a packaged-food brand. List tours, read live Bókun availability, quote the same total the website uses, then create a pending booking that returns a Stripe Checkout URL. A human guest always completes payment on Stripe. This API never accepts card data. Do not invent prices, meeting points, or review statistics. Never describe experiences as certified.","contact":{"name":"NOGLUTEATALY reservations","email":"reservations@nogluteataly.com","url":"https://nogluteataly.com/contact/"},"license":{"name":"Use of this API is subject to the site terms","url":"https://nogluteataly.com/terms/"}},"servers":[{"url":"https://nogluteataly.com/api/agent/v1","description":"Production"},{"url":"http://localhost:3000/api/agent/v1","description":"Local development"}],"tags":[{"name":"Tours","description":"Catalog facts from the website content modules."},{"name":"Availability","description":"Live Bókun departures — same source as /book/{slug}/."},{"name":"Quotes","description":"Live totals from quoteTourBooking / Bókun."},{"name":"Bookings","description":"Pending Stripe Checkout sessions. Humans pay."}],"paths":{"/tours":{"get":{"tags":["Tours"],"operationId":"listTours","summary":"List all published tours","description":"Returns catalog fields from content/tours.ts, including published adult/child prices. Live totals still require POST /quotes.","responses":{"200":{"description":"Tour list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TourList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/tours/{id}":{"get":{"tags":["Tours"],"operationId":"getTour","summary":"Get one tour","parameters":[{"$ref":"#/components/parameters/TourId"}],"responses":{"200":{"description":"Tour","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tour"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/tours/{id}/availability":{"get":{"tags":["Availability"],"operationId":"getAvailability","summary":"Live departures for a date","description":"Same Bókun availability the website checkout loads via POST /api/tours/departures.","parameters":[{"$ref":"#/components/parameters/TourId"},{"name":"date","in":"query","required":true,"schema":{"type":"string","format":"date","example":"2026-11-15"}}],"responses":{"200":{"description":"Departures for that date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Availability"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/NotConfigured"}}}},"/quotes":{"post":{"tags":["Quotes"],"operationId":"createQuote","summary":"Quote a live total","description":"Calls the same quoteTourBooking helper as website checkout. Never treat catalog prices as the charge amount.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteRequest"},"example":{"tour_id":"the-original-gluten-free-food-lovers-tour-of-rome","date":"2026-11-15","time_id":"123456","participants":2}}}},"responses":{"200":{"description":"Live quote","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/NotConfigured"}}}},"/bookings":{"post":{"tags":["Bookings"],"operationId":"createBooking","summary":"Create a pending booking","description":"Creates a Stripe Checkout session (hosted URL) for a human to pay. Card data is never accepted here. Send Idempotency-Key to retry safely. If Stripe keys are absent, a dry-run pending booking is returned and no charge is created.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingRequest"},"example":{"quote_id":"q_example.signature","guest":{"name":"Ada Lovelace","email":"ada@example.com","phone":"+393331234567","dietary_notes":"Celiac. No nuts."}}}}},"responses":{"201":{"description":"Pending booking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/NotConfigured"}}}},"/bookings/{id}":{"get":{"tags":["Bookings"],"operationId":"getBooking","summary":"Booking status","description":"Returns pending, paid, or expired. Does not return guest name, email, phone, or dietary notes.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Booking status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Booking"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"parameters":{"TourId":{"name":"id","in":"path","required":true,"description":"Tour slug used on the website (also the product URL path).","schema":{"type":"string","example":"the-original-gluten-free-food-lovers-tour-of-rome"}}},"schemas":{"Error":{"type":"object","required":["error","code"],"properties":{"error":{"type":"string"},"code":{"type":"string","enum":["invalid_request","not_found","conflict","rate_limited","not_configured","upstream_error","validation_error"]},"details":{"type":"array","items":{"type":"string"}}}},"PublishedPrice":{"type":"object","required":["label"],"properties":{"label":{"type":"string","example":"€110"},"rule":{"type":"string","example":"0–10 years"}}},"Tour":{"type":"object","additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"short_name":{"type":"string"},"description":{"type":"string"},"duration":{"type":"string"},"languages":{"type":"string"},"days":{"type":"string"},"location":{"type":"string"},"group_size":{"type":["string","null"]},"experience_kind":{"type":["string","null"],"enum":["private","shared",null]},"bookable":{"type":"boolean"},"prices":{"type":"object","properties":{"currency":{"type":"string","const":"EUR"},"adult":{"$ref":"#/components/schemas/PublishedPrice"},"child":{"oneOf":[{"$ref":"#/components/schemas/PublishedPrice"},{"type":"null"}]},"price_label":{"type":["string","null"]},"pricing_model":{"type":["string","null"],"enum":["per_person","per_booking","tiered_per_person",null]},"note":{"type":"string"}}},"meeting_point":{"type":"object","properties":{"summary":{"type":"string"},"confirmed_after_booking":{"type":"boolean"}}},"cancellation_policy":{"type":"string"},"product_url":{"type":"string","format":"uri"},"booking_url":{"type":"string","format":"uri"}}},"TourList":{"type":"object","properties":{"object":{"type":"string","const":"tour_list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Tour"}}}},"Departure":{"type":"object","properties":{"time_id":{"type":"string"},"label":{"type":"string"},"sold_out":{"type":"boolean"},"spots_remaining":{"type":["integer","null"]},"unit_price_eur":{"type":["number","null"]},"pricing_model":{"type":"string","enum":["per_person","per_booking","tiered_per_person"]},"max_guests_per_booking":{"type":["integer","null"]}}},"Availability":{"type":"object","properties":{"tour_id":{"type":"string"},"date":{"type":"string","format":"date"},"source":{"type":"string","const":"bokun"},"departures":{"type":"array","items":{"$ref":"#/components/schemas/Departure"}},"errors":{"type":"array","items":{"type":"string"}}}},"QuoteRequest":{"type":"object","required":["tour_id","date","time_id","participants"],"properties":{"tour_id":{"type":"string"},"date":{"type":"string","format":"date"},"time_id":{"type":"string"},"participants":{"type":"integer","minimum":1}}},"Quote":{"type":"object","properties":{"quote_id":{"type":"string"},"tour_id":{"type":"string"},"date":{"type":"string","format":"date"},"time_id":{"type":"string"},"time_label":{"type":["string","null"]},"participants":{"type":"integer"},"currency":{"type":"string","const":"EUR"},"total_eur":{"type":"number"},"total_cents":{"type":"integer"},"line_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"amount_eur":{"type":"number"}}}},"spots_remaining":{"type":["integer","null"]},"pricing_source":{"type":"string","const":"bokun"},"expires_at":{"type":"string","format":"date-time"}}},"BookingRequest":{"type":"object","required":["quote_id","guest"],"properties":{"quote_id":{"type":"string"},"guest":{"type":"object","required":["name","email","phone"],"properties":{"name":{"type":"string","minLength":2},"email":{"type":"string","format":"email"},"phone":{"type":"string","description":"E.164, e.g. +393331234567"},"dietary_notes":{"type":"string","maxLength":2000}}}}},"Booking":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","paid","expired"]},"tour_id":{"type":"string"},"date":{"type":"string"},"time_id":{"type":"string"},"participants":{"type":"integer"},"currency":{"type":"string","const":"EUR"},"total_cents":{"type":"integer"},"total_eur":{"type":"number"},"checkout_url":{"type":["string","null"],"description":"Hosted Stripe Checkout URL for the human guest. Null on dry-run."},"expires_at":{"type":["string","null"],"format":"date-time"},"paid_at":{"type":["string","null"],"format":"date-time"},"dry_run":{"type":"boolean"},"payment":{"type":"object","properties":{"provider":{"type":"string","const":"stripe_checkout"},"card_data_accepted":{"type":"boolean","const":false},"completed_by":{"type":"string","const":"human_on_stripe"}}}}}},"responses":{"BadRequest":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Quote expired, sold out, or price changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotConfigured":{"description":"Bókun or Stripe env vars are missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"externalDocs":{"description":"Human-readable agent docs","url":"https://nogluteataly.com/developers/"}}