{"openapi":"3.1.0","info":{"title":"HorseHQ API","version":"1.0.0","summary":"Public HTTP surface of HorseHQ, barn management software for equestrian businesses.","description":"HorseHQ is barn management software for equestrian businesses. It combines scheduling, horse care and health records, staff coordination, recurring billing, invoicing and online payments in one platform, with an AI assistant (Ask HQ) that answers questions about a barn in English or Spanish.\n\nMost of HorseHQ's data is reached through one authenticated GraphQL endpoint rather than a REST resource per entity. Every record belongs to exactly one organization (a barn), and a request can only ever read or write the records of the organization its session is active in — there is no anonymous or cross-organization read.\n\nCost and rate limits: there is no published per-operation quota today. The unauthenticated endpoints below back forms a person fills in rather than a polling loop — treat them as a few requests per minute per client, and the health probe as one request per 30 seconds. Any endpoint may answer HTTP 429 when throttled: back off exponentially and honour `Retry-After` when it is present.","contact":{"name":"HorseHQ support","email":"help@horsehq.com","url":"https://horsehq.com/contact"},"termsOfService":"https://horsehq.com/terms-of-service","license":{"name":"Proprietary — © Horse HQ, Inc.","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://api.horsehq.com","description":"Production"}],"tags":[{"name":"Discovery","description":"Machine-readable descriptions of this API."},{"name":"Operations","description":"Service status, for monitors and for triage."},{"name":"Contact","description":"Public lead-capture forms on the marketing site. No authentication."},{"name":"GraphQL","description":"The authenticated data endpoint every application feature is built on."}],"paths":{"/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"Fetch this OpenAPI document","description":"Returns the OpenAPI 3.1 description of this API. Unauthenticated, unchanging between deploys except when the surface changes, and safe to cache. The same document is published on the marketing origin at /openapi.json.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"The OpenAPI document.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/api/health":{"get":{"operationId":"getServiceHealth","summary":"Check service health","description":"Reports whether the database, both authentication instances and the GraphQL server are reachable from the API process. Unauthenticated. Answers 200 when every check passes and 503 when any of them fails; the body has the same shape either way, so read `checks` to see which one is down.","tags":["Operations"],"security":[],"responses":{"200":{"description":"Every check passed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthReport"}}}},"503":{"description":"At least one check failed. Read `checks` for which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthReport"}}}}}}},"/api/waitlist":{"post":{"operationId":"joinWaitlist","summary":"Join the product waitlist","description":"Records an email address as a marketing lead. Unauthenticated, and intended for the waitlist form on the marketing site. Sends no email. In production a reCAPTCHA v3 token obtained in the browser is required, so this operation is not usable server-to-server.","tags":["Contact"],"security":[],"requestBody":{"required":true,"description":"The address to record.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistRequest"}}}},"responses":{"200":{"description":"The address was recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormAccepted"}}}},"400":{"description":"The address was missing or malformed, or reCAPTCHA verification failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormRejected"}}}},"500":{"description":"The address could not be recorded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormRejected"}}}}}}},"/api/book-demo":{"post":{"operationId":"requestProductDemo","summary":"Request a product demo","description":"Submits a demo request to the sales team and records the sender as a marketing lead. Unauthenticated, and intended for the demo form on the marketing site. In production a reCAPTCHA v3 token obtained in the browser is required, so this operation is not usable server-to-server.","tags":["Contact"],"security":[],"requestBody":{"required":true,"description":"Who is asking, and how to reach them.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookDemoRequest"}}}},"responses":{"200":{"description":"The request reached the sales team.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormAccepted"}}}},"400":{"description":"A required field was missing, or reCAPTCHA verification failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormRejected"}}}},"500":{"description":"The request could not be delivered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormRejected"}}}}}}},"/api/graphql":{"post":{"operationId":"executeGraphqlOperation","summary":"Execute a GraphQL query or mutation","description":"The single authenticated data endpoint: horses, events and the calendar, people and memberships, invoices, payments, notes and tasks are all read and written here.\n\nAuthentication is the session cookie set by the sign-in flow on the web apps; there is no public API key programme yet, so a caller that cannot present a browser session cannot use this endpoint. Send the `x-horsehq-app` header so the request resolves against the right application. Schema introspection is disabled in production; write to help@horsehq.com for the schema.\n\nAn unauthenticated request receives 200 with a GraphQL error carrying `extensions.code = \"UNAUTHENTICATED\"`, per the GraphQL over HTTP convention, rather than a 401.","tags":["GraphQL"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"x-horsehq-app","in":"header","required":false,"description":"Which application surface the session belongs to. Defaults to the operator app.","schema":{"type":"string","enum":["pro","rider"]}}],"requestBody":{"required":true,"description":"A GraphQL document, its variables and its operation name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphqlRequest"}}}},"responses":{"200":{"description":"A GraphQL response. `errors` may be present with or without `data`; check it before reading `data`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphqlResponse"}}}},"400":{"description":"The request body was not a valid GraphQL request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphqlResponse"}}}},"429":{"description":"The caller is being throttled. Back off and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphqlResponse"}}}}}}}},"components":{"securitySchemes":{"sessionCookie":{"type":"apiKey","in":"cookie","name":"horsehq.session_token","description":"The session cookie issued by the sign-in flow. Scoped to `.horsehq.com`, so it travels to the API origin on its own. Obtained by a person signing in — there is no machine credential flow today."}},"schemas":{"HealthReport":{"type":"object","required":["status","service","timestamp","checks"],"properties":{"status":{"type":"string","enum":["ok","degraded"],"description":"Rolls up every entry of `checks`."},"service":{"type":"string","description":"Which service answered."},"timestamp":{"type":"string","format":"date-time","description":"When the checks ran."},"checks":{"type":"object","required":["db","authPro","authRider","graphqlReady"],"properties":{"db":{"type":"string","enum":["ok","fail"],"description":"The database answered a trivial query."},"authPro":{"type":"string","enum":["ok","fail"],"description":"The operator app auth instance booted."},"authRider":{"type":"string","enum":["ok","fail"],"description":"The rider app auth instance booted."},"graphqlReady":{"type":"string","enum":["ok","fail"],"description":"The GraphQL server finished starting."}}}}},"WaitlistRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"The address to add to the waitlist."},"recaptchaToken":{"type":"string","description":"A reCAPTCHA v3 token for the `waitlist` action. Required in production."}},"additionalProperties":false},"BookDemoRequest":{"type":"object","required":["name","email","phone"],"properties":{"name":{"type":"string","minLength":1,"description":"The requester's full name."},"email":{"type":"string","format":"email","description":"Where to reply."},"phone":{"type":"string","minLength":1,"description":"A phone number to reach the requester on."},"barnName":{"type":"string","description":"The name of their barn or business. Optional."},"comments":{"type":"string","description":"Anything they want the sales team to know first. Optional."},"recaptchaToken":{"type":"string","description":"A reCAPTCHA v3 token for the `book_demo` action. Required in production."}},"additionalProperties":false},"FormAccepted":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean","const":true,"description":"Always true on this response."}}},"FormRejected":{"type":"object","required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false,"description":"Always false on this response."},"error":{"type":"string","description":"What was wrong, in a sentence fit to show a person."}}},"GraphqlRequest":{"type":"object","required":["query"],"properties":{"query":{"type":"string","description":"The GraphQL document to execute."},"operationName":{"type":"string","description":"Which operation in the document to run."},"variables":{"type":"object","additionalProperties":true,"description":"The operation's variables."}}},"GraphqlResponse":{"type":"object","properties":{"data":{"type":["object","null"],"additionalProperties":true,"description":"The result, shaped by the operation. Null when execution failed outright."},"errors":{"type":"array","description":"Present when anything went wrong. `extensions.code` carries the machine-readable reason.","items":{"type":"object","required":["message"],"properties":{"message":{"type":"string"},"path":{"type":"array","items":{"type":["string","integer"]}},"extensions":{"type":"object","additionalProperties":true}}}}}}}}}