{
  "openapi": "3.1.0",
  "info": {
    "title": "Limejade Public API",
    "version": "1.0.0",
    "summary": "Read salon availability and create client appointments on Limejade.",
    "description": "Public HTTP surface of Limejade, the salon management platform at https://limejade.vercel.app.\n\nTwo families of endpoints are published here:\n\n1. **Public booking** — the unauthenticated tRPC procedures behind every salon's `/book/{orgSlug}` page. Use them to list a salon's locations, stylists, and appointment types, check availability for a salon-local day, and create an appointment.\n2. **Agent discovery** — the machine-readable documents (`llms.txt`, pricing, sitemap, MCP manifest) an agent should read before deciding whether to call anything.\n\nAuthenticated staff APIs (clients, appointments, and billing) are intentionally **not** published here. They are reachable only with a signed-in session over tRPC.\n\n### Calling convention\n\nEndpoints are tRPC procedures served over plain HTTP. Queries are `GET` with the input as a URL-encoded `input` query parameter; mutations are `POST` with a JSON body. Both use superjson, so payloads are wrapped in a `{ \"json\": ... }` envelope. Results arrive as `{ \"result\": { \"data\": { \"json\": ... } } }` and errors as `{ \"error\": { \"json\": { ... } } }`.\n\n### Dates and timezones\n\nCalendar dates (`date`, `startDate`, `closedDates`) are **salon-local** `yyyy-MM-dd` strings resolved with the salon's IANA timezone from `getPublicClinic`. Instants (`startTime`) are ISO 8601. Never derive a salon day from a UTC timestamp.\n\n### Rate limits\n\nPublic booking is throttled per salon and per caller. Treat `429` as retryable after the `Retry-After` interval. Booking mutations are idempotent on `idempotencyKey` — reuse the same UUID when retrying so a network failure cannot double-book a client.",
    "termsOfService": "https://limejade.vercel.app/legal/terms",
    "contact": {
      "name": "Limejade support",
      "email": "hello@limejade.com",
      "url": "https://limejade.vercel.app/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://limejade.vercel.app/legal/terms"
    }
  },
  "servers": [
    {
      "url": "https://limejade.vercel.app",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Limejade API and agent integration guide",
    "url": "https://limejade.vercel.app/docs/api"
  },
  "tags": [
    {
      "name": "Public booking",
      "description": "Unauthenticated appointment booking for a single salon, identified by its public slug."
    },
    {
      "name": "Agent discovery",
      "description": "Machine-readable documents describing the product, pricing, and tool surface."
    },
    {
      "name": "Queue display",
      "description": "Token-gated read-only queue board for salon floor screens."
    }
  ],
  "paths": {
    "/api/trpc/public.booking.getOrganization": {
      "get": {
        "operationId": "getPublicClinic",
        "summary": "Get a salon's bookable configuration",
        "description": "Returns the salon's timezone, locations, online-bookable appointment types, participating stylists and beauticians, and booking window. Call this first: every other booking operation needs ids from this response.",
        "tags": [
          "Public booking"
        ],
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "URL-encoded JSON in the superjson envelope, e.g. {\"json\":{\"orgSlug\":\"sunrise-salon\"}}.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "superjson-wrapped procedure input.",
                  "required": [
                    "json"
                  ],
                  "properties": {
                    "json": {
                      "$schema": "https://json-schema.org/draft/2020-12/schema",
                      "type": "object",
                      "properties": {
                        "orgSlug": {
                          "type": "string",
                          "minLength": 1,
                          "description": "Public clinic slug, the same value used in /book/{orgSlug}."
                        }
                      },
                      "required": [
                        "orgSlug"
                      ]
                    },
                    "meta": {
                      "type": "object",
                      "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Procedure result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "result"
                  ],
                  "properties": {
                    "result": {
                      "type": "object",
                      "required": [
                        "data"
                      ],
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "superjson-wrapped procedure output.",
                          "required": [
                            "json"
                          ],
                          "properties": {
                            "json": {
                              "type": "object",
                              "description": "Everything a booking UI or agent needs before it can offer times.",
                              "required": [
                                "id",
                                "name",
                                "locations",
                                "appointmentTypes",
                                "providers"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Organization id."
                                },
                                "name": {
                                  "type": "string",
                                  "description": "Salon display name."
                                },
                                "slug": {
                                  "type": "string",
                                  "description": "Canonical public slug."
                                },
                                "logo": {
                                  "type": [
                                    "string",
                                    "null"
                                  ],
                                  "description": "Salon logo URL."
                                },
                                "currency": {
                                  "type": "string",
                                  "description": "ISO 4217 currency code."
                                },
                                "timezone": {
                                  "type": "string",
                                  "description": "IANA timezone. All calendar dates in this API are salon-local, resolved with this zone."
                                },
                                "bookingWindowDays": {
                                  "type": "integer",
                                  "description": "How many days ahead online booking is allowed."
                                },
                                "bookableWeekdays": {
                                  "type": "array",
                                  "items": {
                                    "type": "integer",
                                    "minimum": 0,
                                    "maximum": 6
                                  },
                                  "description": "Weekdays open to online booking, 0 = Sunday."
                                },
                                "closedDates": {
                                  "type": "array",
                                  "items": {
                                    "type": "string",
                                    "format": "date"
                                  },
                                  "description": "Clinic-local yyyy-MM-dd dates closed to online booking."
                                },
                                "allowOtherAppointmentType": {
                                  "type": "boolean",
                                  "description": "Whether appointmentTypeId may be \"other\" with a free-text description."
                                },
                                "locations": {
                                  "type": "array",
                                  "description": "Active locations that accept online bookings.",
                                  "items": {
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "name"
                                    ],
                                    "properties": {
                                      "id": {
                                        "type": "string",
                                        "format": "uuid"
                                      },
                                      "name": {
                                        "type": "string"
                                      },
                                      "timezone": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "address": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "city": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "state": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "postalCode": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "country": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "phone": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "email": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      }
                                    }
                                  }
                                },
                                "appointmentTypes": {
                                  "type": "array",
                                  "description": "Visit types open to online booking.",
                                  "items": {
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "name",
                                      "duration"
                                    ],
                                    "properties": {
                                      "id": {
                                        "type": "string",
                                        "format": "uuid"
                                      },
                                      "name": {
                                        "type": "string"
                                      },
                                      "duration": {
                                        "type": "integer",
                                        "description": "Scheduled length in minutes."
                                      },
                                      "price": {
                                        "type": [
                                          "number",
                                          "null"
                                        ],
                                        "description": "Indicative price in the salon currency."
                                      },
                                      "requiresConfirmation": {
                                        "type": "boolean",
                                        "description": "When true a new booking starts as scheduled, not confirmed."
                                      }
                                    }
                                  }
                                },
                                "providers": {
                                  "type": "array",
                                  "description": "Clinicians accepting online bookings.",
                                  "items": {
                                    "type": "object",
                                    "required": [
                                      "id"
                                    ],
                                    "properties": {
                                      "id": {
                                        "type": "string",
                                        "format": "uuid"
                                      },
                                      "staffType": {
                                        "type": [
                                          "string",
                                          "null"
                                        ]
                                      },
                                      "user": {
                                        "type": "object",
                                        "properties": {
                                          "name": {
                                            "type": [
                                              "string",
                                              "null"
                                            ]
                                          },
                                          "image": {
                                            "type": [
                                              "string",
                                              "null"
                                            ]
                                          }
                                        }
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                              "additionalProperties": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Input failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "403": {
            "description": "Online booking is disabled for this salon.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "404": {
            "description": "Clinic, location, provider, or appointment type not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/trpc/public.booking.listSlots": {
      "get": {
        "operationId": "listPublicBookingSlots",
        "summary": "List bookable times for one salon-local day",
        "description": "Returns the appointment starts a client can actually book for a given location, stylist, appointment type, and salon-local date. When the list is empty, read `availability.kind` for the server's reason instead of guessing.",
        "tags": [
          "Public booking"
        ],
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "URL-encoded JSON in the superjson envelope, e.g. {\"json\":{\"orgSlug\":\"sunrise-salon\"}}.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "superjson-wrapped procedure input.",
                  "required": [
                    "json"
                  ],
                  "properties": {
                    "json": {
                      "$schema": "https://json-schema.org/draft/2020-12/schema",
                      "type": "object",
                      "properties": {
                        "orgSlug": {
                          "type": "string",
                          "minLength": 1,
                          "description": "Public clinic slug, the same value used in /book/{orgSlug}."
                        },
                        "locationId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                          "description": "Location id from getOrganization.locations."
                        },
                        "providerId": {
                          "description": "Member id of the requested clinician. Use \"any\" or omit to let the clinic assign the first available provider.",
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "string",
                              "const": "any"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "appointmentTypeId": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "string",
                              "const": "other"
                            }
                          ],
                          "description": "Appointment type id from getOrganization.appointmentTypes, or \"other\" to describe the visit in otherAppointmentType."
                        },
                        "date": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                          "description": "Clinic-local calendar date in yyyy-MM-dd. Never a UTC instant — the clinic timezone decides the day."
                        }
                      },
                      "required": [
                        "orgSlug",
                        "locationId",
                        "appointmentTypeId",
                        "date"
                      ]
                    },
                    "meta": {
                      "type": "object",
                      "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Procedure result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "result"
                  ],
                  "properties": {
                    "result": {
                      "type": "object",
                      "required": [
                        "data"
                      ],
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "superjson-wrapped procedure output.",
                          "required": [
                            "json"
                          ],
                          "properties": {
                            "json": {
                              "type": "object",
                              "required": [
                                "slots",
                                "availability"
                              ],
                              "properties": {
                                "slots": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "description": "A bookable appointment start.",
                                    "required": [
                                      "startTime"
                                    ],
                                    "properties": {
                                      "startTime": {
                                        "type": "string",
                                        "format": "date-time",
                                        "description": "ISO 8601 instant to pass back to createBooking."
                                      },
                                      "endTime": {
                                        "type": "string",
                                        "format": "date-time",
                                        "description": "ISO 8601 instant the appointment would end."
                                      },
                                      "remaining": {
                                        "type": "integer",
                                        "description": "Seats left in this slot, present only when the salon publishes remaining capacity."
                                      }
                                    }
                                  }
                                },
                                "availability": {
                                  "type": "object",
                                  "description": "Server-derived reason a day has no bookable time. Never infer a reason from an empty slots array.",
                                  "required": [
                                    "kind"
                                  ],
                                  "properties": {
                                    "kind": {
                                      "type": "string",
                                      "enum": [
                                        "available",
                                        "doctor_unavailable",
                                        "clinic_closed",
                                        "fully_booked",
                                        "no_online_appointments"
                                      ],
                                      "description": "Why the day looks the way it does."
                                    },
                                    "detail": {
                                      "type": "string",
                                      "description": "Optional qualifier, e.g. \"horizon\" when the date is past the salon booking window."
                                    }
                                  }
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                              "additionalProperties": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Input failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "403": {
            "description": "Online booking is disabled for this salon.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "404": {
            "description": "Clinic, location, provider, or appointment type not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/trpc/public.booking.listSlotCounts": {
      "get": {
        "operationId": "listPublicBookingSlotCounts",
        "summary": "Summarise availability across a date range",
        "description": "Returns a per-day count of bookable slots for up to 90 salon-local days. Use it to pick a promising day before calling listPublicBookingSlots, rather than polling each date.",
        "tags": [
          "Public booking"
        ],
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "URL-encoded JSON in the superjson envelope, e.g. {\"json\":{\"orgSlug\":\"sunrise-salon\"}}.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "superjson-wrapped procedure input.",
                  "required": [
                    "json"
                  ],
                  "properties": {
                    "json": {
                      "$schema": "https://json-schema.org/draft/2020-12/schema",
                      "type": "object",
                      "properties": {
                        "orgSlug": {
                          "type": "string",
                          "minLength": 1,
                          "description": "Public clinic slug, the same value used in /book/{orgSlug}."
                        },
                        "locationId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                          "description": "Location id from getOrganization.locations."
                        },
                        "providerId": {
                          "description": "Member id of the requested clinician. Use \"any\" or omit to let the clinic assign the first available provider.",
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "string",
                              "const": "any"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "appointmentTypeId": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "string",
                              "const": "other"
                            }
                          ],
                          "description": "Appointment type id from getOrganization.appointmentTypes, or \"other\" to describe the visit in otherAppointmentType."
                        },
                        "startDate": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                          "description": "First clinic-local day of the window, in yyyy-MM-dd."
                        },
                        "days": {
                          "default": 14,
                          "description": "Number of consecutive days to summarise. Clamped to the clinic booking window.",
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 90
                        }
                      },
                      "required": [
                        "orgSlug",
                        "locationId",
                        "appointmentTypeId",
                        "startDate"
                      ]
                    },
                    "meta": {
                      "type": "object",
                      "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Procedure result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "result"
                  ],
                  "properties": {
                    "result": {
                      "type": "object",
                      "required": [
                        "data"
                      ],
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "superjson-wrapped procedure output.",
                          "required": [
                            "json"
                          ],
                          "properties": {
                            "json": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "required": [
                                  "date",
                                  "count",
                                  "availability"
                                ],
                                "properties": {
                                  "date": {
                                    "type": "string",
                                    "format": "date"
                                  },
                                  "count": {
                                    "type": "integer",
                                    "description": "Number of bookable starts on that day."
                                  },
                                  "availability": {
                                    "type": "object",
                                    "description": "Server-derived reason a day has no bookable time. Never infer a reason from an empty slots array.",
                                    "required": [
                                      "kind"
                                    ],
                                    "properties": {
                                      "kind": {
                                        "type": "string",
                                        "enum": [
                                          "available",
                                          "doctor_unavailable",
                                          "clinic_closed",
                                          "fully_booked",
                                          "no_online_appointments"
                                        ],
                                        "description": "Why the day looks the way it does."
                                      },
                                      "detail": {
                                        "type": "string",
                                        "description": "Optional qualifier, e.g. \"horizon\" when the date is past the salon booking window."
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                              "additionalProperties": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Input failed validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "403": {
            "description": "Online booking is disabled for this salon.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "404": {
            "description": "Clinic, location, provider, or appointment type not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/trpc/public.booking.createBooking": {
      "post": {
        "operationId": "createPublicBooking",
        "summary": "Book an appointment for a client",
        "description": "Creates an appointment at a start time returned by listPublicBookingSlots and registers the client if they are new to the salon. Idempotent on `idempotencyKey`: replaying the same key returns the original appointment rather than booking a second one. A `409` means the slot was taken between listing and booking — re-list and try another time.",
        "tags": [
          "Public booking"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "superjson-wrapped procedure input.",
                "required": [
                  "json"
                ],
                "properties": {
                  "json": {
                    "$schema": "https://json-schema.org/draft/2020-12/schema",
                    "type": "object",
                    "properties": {
                      "orgSlug": {
                        "type": "string",
                        "minLength": 1,
                        "description": "Public clinic slug, the same value used in /book/{orgSlug}."
                      },
                      "locationId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                        "description": "Location id from getOrganization.locations."
                      },
                      "providerId": {
                        "description": "Member id of the requested clinician. Use \"any\" or omit to let the clinic assign the first available provider.",
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "string",
                            "const": "any"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "appointmentTypeId": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "string",
                            "const": "other"
                          }
                        ],
                        "description": "Appointment type id from getOrganization.appointmentTypes, or \"other\" to describe the visit in otherAppointmentType."
                      },
                      "otherAppointmentType": {
                        "description": "Free-text visit type. Required when appointmentTypeId is \"other\".",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "startTime": {
                        "description": "Appointment start as an ISO 8601 instant, taken from a listSlots result."
                      },
                      "firstName": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100,
                        "description": "Patient given name."
                      },
                      "lastName": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 100,
                        "description": "Patient family name."
                      },
                      "email": {
                        "description": "Patient email. Either email or phone is required.",
                        "type": "string",
                        "format": "email",
                        "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                      },
                      "phone": {
                        "description": "Patient phone. Either email or phone is required.",
                        "type": "string",
                        "minLength": 7
                      },
                      "reasonForVisit": {
                        "description": "Optional free-text reason shown to the clinic.",
                        "type": "string",
                        "maxLength": 2000
                      },
                      "idempotencyKey": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                        "description": "Client-generated UUID. Retrying with the same key returns the original appointment instead of double-booking."
                      },
                      "captchaToken": {
                        "description": "Cloudflare Turnstile token from the booking confirmation step. Required in production.",
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 2048
                      }
                    },
                    "required": [
                      "orgSlug",
                      "locationId",
                      "appointmentTypeId",
                      "startTime",
                      "firstName",
                      "lastName",
                      "idempotencyKey"
                    ]
                  },
                  "meta": {
                    "type": "object",
                    "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Appointment created, or the replay of a prior create.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "result"
                  ],
                  "properties": {
                    "result": {
                      "type": "object",
                      "required": [
                        "data"
                      ],
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "superjson-wrapped procedure output.",
                          "required": [
                            "json"
                          ],
                          "properties": {
                            "json": {
                              "type": "object",
                              "required": [
                                "id",
                                "status",
                                "startTime",
                                "endTime"
                              ],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "description": "Appointment id."
                                },
                                "status": {
                                  "type": "string",
                                  "enum": [
                                    "scheduled",
                                    "confirmed"
                                  ],
                                  "description": "`scheduled` when the salon reviews bookings manually, `confirmed` when it auto-accepts."
                                },
                                "startTime": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "endTime": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "providerId": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "providerName": {
                                  "type": "string",
                                  "description": "Resolved stylist or beautician, useful when providerId was \"any\"."
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                              "additionalProperties": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation failed, or the date falls outside the salon booking window.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "403": {
            "description": "Online booking is disabled for this salon.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "404": {
            "description": "Clinic, location, provider, or appointment type not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          },
          "409": {
            "description": "The slot was taken while the request was in flight.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/trpc/public.queueDisplay.getBoard": {
      "get": {
        "operationId": "getPublicQueueBoard",
        "summary": "Read a waiting room queue board",
        "description": "Returns the masked waiting list for one salon location. Requires the unguessable display token issued to that location's screen, so it is not usable for general salon lookups.",
        "tags": [
          "Queue display"
        ],
        "parameters": [
          {
            "name": "input",
            "in": "query",
            "required": true,
            "description": "URL-encoded superjson envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "superjson-wrapped procedure input.",
                  "required": [
                    "json"
                  ],
                  "properties": {
                    "json": {
                      "$schema": "https://json-schema.org/draft/2020-12/schema",
                      "type": "object",
                      "properties": {
                        "locationId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "token": {
                          "type": "string",
                          "minLength": 16,
                          "maxLength": 200
                        }
                      },
                      "required": [
                        "locationId",
                        "token"
                      ]
                    },
                    "meta": {
                      "type": "object",
                      "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current board state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "result"
                  ],
                  "properties": {
                    "result": {
                      "type": "object",
                      "required": [
                        "data"
                      ],
                      "properties": {
                        "data": {
                          "type": "object",
                          "description": "superjson-wrapped procedure output.",
                          "required": [
                            "json"
                          ],
                          "properties": {
                            "json": {
                              "type": "object",
                              "required": [
                                "organizationName",
                                "locationName",
                                "tickets"
                              ],
                              "properties": {
                                "organizationName": {
                                  "type": "string"
                                },
                                "locationName": {
                                  "type": "string"
                                },
                                "expiresAt": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "updatedAt": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "tickets": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "required": [
                                      "id",
                                      "queueNumber",
                                      "displayName",
                                      "status"
                                    ],
                                    "properties": {
                                      "id": {
                                        "type": "string"
                                      },
                                      "queueNumber": {
                                        "type": "integer"
                                      },
                                      "displayName": {
                                        "type": "string",
                                        "description": "Patient name masked for public display."
                                      },
                                      "status": {
                                        "type": "string",
                                        "enum": [
                                          "waiting",
                                          "inService",
                                          "withDoctor"
                                        ]
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "meta": {
                              "type": "object",
                              "description": "superjson type metadata. Optional for callers; Date values may be sent as ISO strings without it.",
                              "additionalProperties": true
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown, disabled, or expired display link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrpcError"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "Product overview for language models",
        "description": "llms.txt: what Limejade is, when an agent should reach for it, and the canonical URLs for every public topic.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/pricing.md": {
      "get": {
        "operationId": "getPricingMarkdown",
        "summary": "Machine-readable pricing",
        "description": "Published list prices per plan and add-on in markdown. Prefer this over paraphrased third-party quotes.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiDocument",
        "summary": "This document",
        "description": "The OpenAPI 3.1 description of this API.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/openapi.yaml": {
      "get": {
        "operationId": "getOpenApiDocumentYaml",
        "summary": "This document, as YAML",
        "description": "The same OpenAPI 3.1 description, rendered as YAML.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp": {
      "get": {
        "operationId": "getMcpManifest",
        "summary": "MCP server manifest",
        "description": "Model Context Protocol manifest describing the Streamable HTTP endpoint and the read-only tools it exposes.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callMcpEndpoint",
        "summary": "MCP Streamable HTTP transport",
        "description": "Read-only Model Context Protocol server. Send a JSON-RPC 2.0 request; supported methods are server/discover, initialize, ping, tools/list, and tools/call. Stateless: no session is established and no session header is required. Prefer an MCP client over calling this directly.",
        "tags": [
          "Agent discovery"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "const": "2.0"
                  },
                  "id": {
                    "description": "Omit for notifications, which are answered with 202 and no body.",
                    "anyOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ]
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "server/discover",
                      "initialize",
                      "ping",
                      "tools/list",
                      "tools/call"
                    ]
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              },
              "examples": {
                "listTools": {
                  "summary": "List the available tools",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/list"
                  }
                },
                "callTool": {
                  "summary": "Search the documentation",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/call",
                    "params": {
                      "name": "search_docs",
                      "arguments": {
                        "query": "recurring appointments"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "jsonrpc"
                  ],
                  "properties": {
                    "jsonrpc": {
                      "type": "string",
                      "const": "2.0"
                    },
                    "id": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "integer"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "result": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "integer"
                        },
                        "message": {
                          "type": "string"
                        },
                        "data": {
                          "type": "object",
                          "additionalProperties": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Notification accepted; no body."
          },
          "400": {
            "description": "Malformed JSON-RPC, header mismatch, or unsupported protocol version."
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemapIndex",
        "summary": "Sitemap index",
        "description": "Index of the marketing, blog, docs, and legal sitemaps.",
        "tags": [
          "Agent discovery"
        ],
        "responses": {
          "200": {
            "description": "Document contents.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TrpcError": {
        "type": "object",
        "description": "tRPC error envelope. `error.json.data.code` is the stable machine code; `httpStatus` mirrors it.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "json"
            ],
            "properties": {
              "json": {
                "type": "object",
                "required": [
                  "message",
                  "code"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  },
                  "code": {
                    "type": "integer",
                    "description": "JSON-RPC error code."
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "code": {
                        "type": "string",
                        "enum": [
                          "BAD_REQUEST",
                          "UNAUTHORIZED",
                          "FORBIDDEN",
                          "NOT_FOUND",
                          "CONFLICT",
                          "TOO_MANY_REQUESTS",
                          "INTERNAL_SERVER_ERROR"
                        ],
                        "description": "Stable machine-readable error code."
                      },
                      "httpStatus": {
                        "type": "integer"
                      },
                      "path": {
                        "type": "string",
                        "description": "Procedure that produced the error."
                      },
                      "zodError": {
                        "type": [
                          "object",
                          "null"
                        ],
                        "description": "Flattened field errors when input validation failed.",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ApiError": {
        "type": "object",
        "description": "JSON error body returned by every non-tRPC endpoint under this origin.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "hint",
              "docs"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "bad_request",
                  "unauthorized",
                  "forbidden",
                  "not_found",
                  "method_not_allowed",
                  "not_acceptable",
                  "conflict",
                  "payload_too_large",
                  "unsupported_media_type",
                  "rate_limited",
                  "internal_error",
                  "service_unavailable"
                ],
                "description": "Stable error code to branch on."
              },
              "message": {
                "type": "string",
                "description": "Human-readable explanation. May change between releases."
              },
              "hint": {
                "type": "string",
                "description": "What the caller should do next to recover."
              },
              "docs": {
                "type": "string",
                "format": "uri",
                "description": "Where to read more."
              },
              "details": {
                "description": "Optional structured context, e.g. field-level errors."
              }
            }
          }
        }
      },
      "AvailabilitySummary": {
        "type": "object",
        "description": "Server-derived reason a day has no bookable time. Never infer a reason from an empty slots array.",
        "required": [
          "kind"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "available",
              "doctor_unavailable",
              "clinic_closed",
              "fully_booked",
              "no_online_appointments"
            ],
            "description": "Why the day looks the way it does."
          },
          "detail": {
            "type": "string",
            "description": "Optional qualifier, e.g. \"horizon\" when the date is past the salon booking window."
          }
        }
      },
      "BookingSlot": {
        "type": "object",
        "description": "A bookable appointment start.",
        "required": [
          "startTime"
        ],
        "properties": {
          "startTime": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 instant to pass back to createBooking."
          },
          "endTime": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 instant the appointment would end."
          },
          "remaining": {
            "type": "integer",
            "description": "Seats left in this slot, present only when the salon publishes remaining capacity."
          }
        }
      },
      "PublicClinic": {
        "type": "object",
        "description": "Everything a booking UI or agent needs before it can offer times.",
        "required": [
          "id",
          "name",
          "locations",
          "appointmentTypes",
          "providers"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Organization id."
          },
          "name": {
            "type": "string",
            "description": "Salon display name."
          },
          "slug": {
            "type": "string",
            "description": "Canonical public slug."
          },
          "logo": {
            "type": [
              "string",
              "null"
            ],
            "description": "Salon logo URL."
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code."
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone. All calendar dates in this API are salon-local, resolved with this zone."
          },
          "bookingWindowDays": {
            "type": "integer",
            "description": "How many days ahead online booking is allowed."
          },
          "bookableWeekdays": {
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 0,
              "maximum": 6
            },
            "description": "Weekdays open to online booking, 0 = Sunday."
          },
          "closedDates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Clinic-local yyyy-MM-dd dates closed to online booking."
          },
          "allowOtherAppointmentType": {
            "type": "boolean",
            "description": "Whether appointmentTypeId may be \"other\" with a free-text description."
          },
          "locations": {
            "type": "array",
            "description": "Active locations that accept online bookings.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "timezone": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "address": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "city": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "state": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "postalCode": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "country": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "phone": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "email": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          },
          "appointmentTypes": {
            "type": "array",
            "description": "Visit types open to online booking.",
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "duration"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "duration": {
                  "type": "integer",
                  "description": "Scheduled length in minutes."
                },
                "price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Indicative price in the salon currency."
                },
                "requiresConfirmation": {
                  "type": "boolean",
                  "description": "When true a new booking starts as scheduled, not confirmed."
                }
              }
            }
          },
          "providers": {
            "type": "array",
            "description": "Clinicians accepting online bookings.",
            "items": {
              "type": "object",
              "required": [
                "id"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "staffType": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "user": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "image": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
