GraphQL API
Reservory's GraphQL API is a flexible alternative to REST for discovery and the booking flow. It supports queries, mutations, fragments, aliases, @include/@skip directives, and introspection.
Endpoint
POST https://api.reservory.com/api/graphql
GET https://api.reservory.com/api/graphql # returns { sdl } for toolingCurrent Limitations
- Public surface only: discovery + booking flow. Operator-scoped queries (bookings, customers, refunds) are REST-only for now.
- Input objects via variables: pass input objects (e.g.
CreateBookingInput) through a$variable, not as inline object literals. - No subscriptions: use webhooks for real-time events.
- Rate limit: 60 requests/minute per IP.
Example Queries
Get Experience Metadata
query GetExperience($tenant: String!, $experience: String!) {
experience(tenant: $tenant, experience: $experience) {
id
name
slug
currency
basePriceCents
minPartySize
maxPartySize
durationMinutes
requiresWaiver
}
}
# Variables:
# { "tenant": "acme-escape", "experience": "the-vault" }List Available Slots
query AvailableSlots($expId: ID!, $from: String, $to: String) {
availableSlots(experienceId: $expId, fromIso: $from, toIso: $to) {
id
startsAt
endsAt
capacity
seatsRemaining
priceCents
}
}
# Variables:
# {
# "expId": "00000000-0000-0000-0000-0000000000aa",
# "from": "2026-05-25T00:00:00Z",
# "to": "2026-06-01T23:59:59Z"
# }Mutations
Create Booking
mutation CreateBooking($input: CreateBookingInput!) {
createBooking(input: $input) {
booking_id
booking_token
}
}
# Variables:
# {
# "input": {
# "hold_id": "...",
# "slot_id": "...",
# "experience_id": "...",
# "venue_id": "...",
# "customer_email": "alice@example.com",
# "customer_first_name": "Alice",
# "guest_count": 2
# }
# }Cancel Booking (by token)
mutation CancelBooking($token: String!) {
cancelBookingByToken(token: $token) {
ok
reason
}
}
# Variables:
# { "token": "<booking_token from createBooking>" }Schema
The live SDL is served from GET /api/graphql as { sdl } (and via introspection):
type Query {
experience(tenant: String!, experience: String!): Experience
availableSlots(experienceId: ID!, fromIso: String, toIso: String): [Slot!]!
}
type Mutation {
createBooking(input: CreateBookingInput!): BookingResponse!
cancelBookingByToken(token: String!): CancelBookingResponse!
}
input CreateBookingInput {
hold_id: ID!
slot_id: ID!
experience_id: ID!
venue_id: ID!
customer_email: String!
customer_first_name: String!
customer_last_name: String
customer_phone: String
guest_count: Int!
}
type Experience {
id: ID!
name: String!
slug: String!
currency: String!
basePriceCents: Int!
minPartySize: Int!
maxPartySize: Int!
durationMinutes: Int!
requiresWaiver: Boolean!
}
type Slot {
id: ID!
startsAt: String!
endsAt: String!
capacity: Int!
seatsRemaining: Int!
priceCents: Int
}
type BookingResponse { booking_id: ID! booking_token: String! }
type CancelBookingResponse { ok: Boolean! reason: String }JavaScript Example
const query = `
query AvailableSlots($expId: ID!) {
availableSlots(experienceId: $expId) {
id
startsAt
seatsRemaining
}
}
`;
const response = await fetch('https://api.reservory.com/api/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query,
variables: { expId: '00000000-0000-0000-0000-0000000000aa' },
}),
});
const { data, errors } = await response.json();
if (errors) console.error(errors);
else console.log(data.availableSlots);Future Roadmap
- Operator-scoped queries (bookings, customers, refunds) with API-key auth
- Subscriptions for real-time slot updates
- Migration to a spec-compliant server (graphql-yoga)