{"openapi":"3.1.0","info":{"title":"TrueTrail API","version":"0.1.0","description":"Kennel operating system API"},"components":{"schemas":{},"parameters":{}},"paths":{"/api/v1/health":{"get":{"tags":["System"],"responses":{"200":{"description":"API health check","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"version":{"type":"string"}},"required":["status"]}}}}}}},"/api/v1/auth/register":{"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"trailName":{"type":"string","minLength":2,"maxLength":80},"legalName":{"type":"string","minLength":1,"maxLength":120},"tosAccepted":{"type":"boolean","enum":[true]}},"required":["email","trailName","tosAccepted"]}}}},"responses":{"201":{"description":"Account created"},"400":{"description":"Terms not accepted"},"403":{"description":"Local registration disabled"},"409":{"description":"Email already registered"}}}},"/api/v1/auth/sign-in/local":{"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Signed in (dev passwordless)"},"403":{"description":"Disabled"},"404":{"description":"No account"}}}},"/api/v1/auth/clerk-sync":{"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"trailName":{"type":"string","minLength":2,"maxLength":80},"legalName":{"type":"string","minLength":1,"maxLength":120},"tosAccepted":{"type":"boolean","enum":[true]}}}}}},"responses":{"200":{"description":"User synced"},"400":{"description":"Terms not accepted"},"401":{"description":"Invalid token"},"503":{"description":"Clerk not configured"}}}},"/api/v1/auth/google-sync":{"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"trailName":{"type":"string","minLength":2,"maxLength":80},"legalName":{"type":"string","minLength":1,"maxLength":120},"tosAccepted":{"type":"boolean","enum":[true]}}}}}},"responses":{"200":{"description":"User synced"},"400":{"description":"Profile incomplete"},"401":{"description":"Invalid Google token"},"503":{"description":"Google auth not configured"}}}},"/api/v1/users/me":{"get":{"tags":["Auth"],"responses":{"200":{"description":"Current user profile"},"401":{"description":"Not signed in"}}},"patch":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"trailName":{"type":"string","minLength":2,"maxLength":80},"legalName":{"type":"string","minLength":1,"maxLength":120},"bio":{"type":"string","maxLength":500},"pronouns":{"type":"string","maxLength":40},"homeKennelId":{"type":"string","nullable":true,"format":"uuid"},"showTrailNamePublic":{"type":"boolean"},"showRunCountsPublic":{"type":"boolean"},"showHomeKennelPublic":{"type":"boolean"},"showAttendancePublic":{"type":"boolean"},"showPostsPublic":{"type":"boolean"},"showRidesharePublic":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated profile"},"400":{"description":"Home kennel is not a joined kennel"},"401":{"description":"Not signed in"}}},"delete":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"string"}},"required":["confirm"]}}}},"responses":{"200":{"description":"Account deleted"},"400":{"description":"Confirmation phrase did not match"},"401":{"description":"Not signed in"},"409":{"description":"Last GM of a kennel"}}}},"/api/v1/users/me/avatar":{"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dataUrl":{"type":"string","minLength":32,"maxLength":450000}},"required":["dataUrl"]}}}},"responses":{"200":{"description":"Profile photo saved"},"400":{"description":"Photo must be a JPEG, PNG, or WebP"},"401":{"description":"Not signed in"}}},"delete":{"tags":["Auth"],"responses":{"200":{"description":"Profile photo removed"},"401":{"description":"Not signed in"}}}},"/api/v1/users/{userId}/public":{"get":{"tags":["Auth"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"responses":{"200":{"description":"Public profile fields only"},"404":{"description":"Not found or hidden"}}}},"/api/v1/users/me/blocks":{"get":{"tags":["Auth"],"responses":{"200":{"description":"Accounts you have blocked"},"401":{"description":"Not signed in"}}},"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"blockedUserId":{"type":"string","format":"uuid"}},"required":["blockedUserId"]}}}},"responses":{"200":{"description":"Already blocked"},"201":{"description":"Blocked"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/blocks/{blockedUserId}":{"delete":{"tags":["Auth"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"blockedUserId","in":"path"}],"responses":{"200":{"description":"Unblocked"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/security":{"get":{"tags":["Auth"],"responses":{"200":{"description":"Privileged-role status for MFA prompts"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/export":{"get":{"tags":["Auth"],"responses":{"200":{"description":"Personal data export"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/sessions":{"get":{"tags":["Auth"],"responses":{"200":{"description":"Browsers signed in to this account"},"401":{"description":"Not signed in"}}},"post":{"tags":["Auth"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sessionId":{"type":"string","format":"uuid"},"label":{"type":"string","minLength":1,"maxLength":120}}}}}},"responses":{"200":{"description":"Existing session still active"},"201":{"description":"Session recorded"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/sessions/{sessionId}/revoke":{"post":{"tags":["Auth"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"sessionId","in":"path"}],"responses":{"200":{"description":"Session revoked"},"401":{"description":"Not signed in"},"404":{"description":"Session not found"}}}},"/api/v1/discover":{"get":{"tags":["Discover"],"parameters":[{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lat","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lng","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"radiusKm","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string"},"required":false,"name":"zip","in":"query"},{"schema":{"type":"string"},"required":false,"name":"city","in":"query"}],"responses":{"200":{"description":"Kennels and events matching discovery query","content":{"application/json":{"schema":{"type":"object","properties":{"kennels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"tagline":{"type":"string"},"location":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"scheduleDescription":{"type":"string"},"typicalCostCents":{"type":"integer"},"websiteUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pageBlocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string"},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"]},"enabled":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"nullable":true}}},"required":["blockType","sortOrder","visibility","enabled"]}},"distanceKm":{"type":"number"}},"required":["id","slug","name","createdAt"]}},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"kennelSlug":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string","minLength":1},"eventType":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string"},"locationName":{"type":"string"},"hashCashCents":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true},"isPublic":{"type":"boolean"},"lifecycleStatus":{"type":"string","enum":["draft","published","canceled"]},"publishedAt":{"type":"string","format":"date-time"},"goingCount":{"type":"integer","minimum":0},"waitlistCount":{"type":"integer","minimum":0},"payableItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"paymentProfileId":{"type":"string","format":"uuid"},"itemType":{"type":"string","enum":["trail_fee","event_rego","merch","donation","addon"]},"title":{"type":"string"},"amountCents":{"type":"integer","minimum":0},"currency":{"type":"string"},"eventId":{"type":"string","format":"uuid"},"confirmationRequired":{"type":"boolean"}},"required":["id","kennelId","itemType","title","amountCents","currency"]},"distanceKm":{"type":"number"}},"required":["id","kennelId","slug","title","eventType","startsAt","isPublic","lifecycleStatus"]}},"mapPins":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["kennel","event"]},"lat":{"type":"number"},"lng":{"type":"number"},"label":{"type":"string"},"href":{"type":"string"},"distanceKm":{"type":"number"}},"required":["id","kind","lat","lng","label"]}},"searchEngine":{"type":"string","enum":["postgres","meilisearch"]}},"required":["kennels","events"]}}}},"400":{"description":"Zip code could not be resolved"}}}},"/api/v1/search":{"get":{"tags":["Discover"],"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"q","in":"query"}],"responses":{"200":{"description":"Full-text search across kennels and public events","content":{"application/json":{"schema":{"type":"object","properties":{"kennels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"tagline":{"type":"string"},"location":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"scheduleDescription":{"type":"string"},"typicalCostCents":{"type":"integer"},"websiteUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pageBlocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string"},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"]},"enabled":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"nullable":true}}},"required":["blockType","sortOrder","visibility","enabled"]}},"distanceKm":{"type":"number"}},"required":["id","slug","name","createdAt"]}},"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"kennelSlug":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string","minLength":1},"eventType":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string"},"locationName":{"type":"string"},"hashCashCents":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true},"isPublic":{"type":"boolean"},"lifecycleStatus":{"type":"string","enum":["draft","published","canceled"]},"publishedAt":{"type":"string","format":"date-time"},"goingCount":{"type":"integer","minimum":0},"waitlistCount":{"type":"integer","minimum":0},"payableItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"paymentProfileId":{"type":"string","format":"uuid"},"itemType":{"type":"string","enum":["trail_fee","event_rego","merch","donation","addon"]},"title":{"type":"string"},"amountCents":{"type":"integer","minimum":0},"currency":{"type":"string"},"eventId":{"type":"string","format":"uuid"},"confirmationRequired":{"type":"boolean"}},"required":["id","kennelId","itemType","title","amountCents","currency"]},"distanceKm":{"type":"number"}},"required":["id","kennelId","slug","title","eventType","startsAt","isPublic","lifecycleStatus"]}},"mapPins":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["kennel","event"]},"lat":{"type":"number"},"lng":{"type":"number"},"label":{"type":"string"},"href":{"type":"string"},"distanceKm":{"type":"number"}},"required":["id","kind","lat","lng","label"]}},"searchEngine":{"type":"string","enum":["postgres","meilisearch"]}},"required":["kennels","events"]}}}},"400":{"description":"Zip code could not be resolved"}}}},"/api/v1/discover/search-backend":{"get":{"tags":["Discover"],"responses":{"200":{"description":"Which discovery search backend is active","content":{"application/json":{"schema":{"type":"object","properties":{"meilisearchConfigured":{"type":"boolean"},"defaultEngine":{"type":"string","enum":["postgres","meilisearch"]}},"required":["meilisearchConfigured","defaultEngine"]}}}}}}},"/api/v1/discover/meilisearch/sync":{"post":{"tags":["Discover"],"responses":{"200":{"description":"Reindex public kennels/events into Meilisearch (when configured)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"reason":{"type":"string"}},"required":["ok"]}}}}}}},"/api/v1/kennels/{slug}":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Kennel hub metadata and page blocks","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"tagline":{"type":"string"},"location":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"scheduleDescription":{"type":"string"},"typicalCostCents":{"type":"integer"},"websiteUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pageBlocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string"},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"]},"enabled":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"nullable":true}}},"required":["blockType","sortOrder","visibility","enabled"]}}},"required":["id","slug","name","createdAt"]}}}},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/page":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"pageSlug","in":"query"},{"schema":{"type":"string","enum":["0","1"]},"required":false,"name":"recordView","in":"query"}],"responses":{"200":{"description":"Live kennel page view model","content":{"application/json":{"schema":{"type":"object","properties":{"kennel":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"tagline":{"type":"string"},"location":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"scheduleDescription":{"type":"string"},"typicalCostCents":{"type":"integer"},"websiteUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pageBlocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string"},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"]},"enabled":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"nullable":true}}},"required":["blockType","sortOrder","visibility","enabled"]}}},"required":["id","slug","name","createdAt"]},"nextEvent":{"nullable":true},"upcomingEvents":{"type":"array","items":{"nullable":true}},"announcements":{"type":"array","items":{"nullable":true}},"mismanagement":{"type":"array","items":{"nullable":true}},"photos":{"type":"array","items":{"nullable":true}},"merch":{"type":"array","items":{"nullable":true}}},"required":["kennel","announcements","mismanagement","photos","merch"]}}}},"404":{"description":"Not found"}}}},"/api/v1/kennels/by-domain/{hostname}":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"hostname","in":"path"}],"responses":{"200":{"description":"Resolve kennel slug from verified custom domain","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"customDomain":{"type":"string"},"verified":{"type":"boolean"}},"required":["slug","customDomain","verified"]}}}},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/member-directory":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Member directory (privacy-aware)"},"404":{"description":"Not found"}}}},"/api/v1/kennels":{"get":{"tags":["Kennels"],"responses":{"200":{"description":"All kennels","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1},"name":{"type":"string","minLength":1},"tagline":{"type":"string"},"location":{"type":"string"},"country":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"scheduleDescription":{"type":"string"},"typicalCostCents":{"type":"integer"},"websiteUrl":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"pageBlocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string"},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"]},"enabled":{"type":"boolean"},"config":{"type":"object","additionalProperties":{"nullable":true}}},"required":["blockType","sortOrder","visibility","enabled"]}}},"required":["id","slug","name","createdAt"]}}}}}}}},"/api/v1/users/me/kennels":{"get":{"tags":["Kennels"],"responses":{"200":{"description":"Kennels the signed-in user has joined"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{slug}/join":{"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["member","visitor","temporary"]}}}}}},"responses":{"200":{"description":"Already a member or request already pending"},"201":{"description":"Joined the kennel or recorded a request"},"401":{"description":"Not signed in"},"403":{"description":"Kennel is not open to join, or the account is restricted"},"404":{"description":"Kennel not found"}}},"delete":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Left the kennel"},"401":{"description":"Not signed in"},"404":{"description":"Kennel not found"}}}},"/api/v1/kennels/{slug}/follow":{"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Already following"},"201":{"description":"Following the kennel"},"401":{"description":"Not signed in"},"403":{"description":"Private kennel"},"404":{"description":"Kennel not found"}}},"delete":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Stopped following"},"401":{"description":"Not signed in"},"404":{"description":"Kennel not found"}}}},"/api/v1/users/me/follows":{"get":{"tags":["Kennels"],"responses":{"200":{"description":"Kennels the signed-in user follows"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{slug}/membership":{"patch":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"isPublic":{"type":"boolean"}},"required":["isPublic"]}}}},"responses":{"200":{"description":"Membership visibility updated"},"401":{"description":"Not signed in"},"404":{"description":"Not a member"}}}},"/api/v1/kennels/{kennelSlug}/events":{"get":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Events for kennel"},"404":{"description":"Not found"}}},"post":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":80,"pattern":"^[a-z0-9-]+$"},"title":{"type":"string","minLength":1},"eventType":{"type":"string","minLength":1},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string","maxLength":4000},"locationName":{"type":"string","maxLength":200},"isPublic":{"type":"boolean"},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true},"hashCashCents":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"}},"required":["slug","title","eventType","startsAt"]}}}},"responses":{"201":{"description":"Draft event created"},"403":{"description":"Forbidden"},"409":{"description":"Slug taken"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}":{"get":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Event detail","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"kennelSlug":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string","minLength":1},"eventType":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string"},"locationName":{"type":"string"},"hashCashCents":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true},"isPublic":{"type":"boolean"},"lifecycleStatus":{"type":"string","enum":["draft","published","canceled"]},"publishedAt":{"type":"string","format":"date-time"},"goingCount":{"type":"integer","minimum":0},"waitlistCount":{"type":"integer","minimum":0},"payableItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kennelId":{"type":"string","format":"uuid"},"paymentProfileId":{"type":"string","format":"uuid"},"itemType":{"type":"string","enum":["trail_fee","event_rego","merch","donation","addon"]},"title":{"type":"string"},"amountCents":{"type":"integer","minimum":0},"currency":{"type":"string"},"eventId":{"type":"string","format":"uuid"},"confirmationRequired":{"type":"boolean"}},"required":["id","kennelId","itemType","title","amountCents","currency"]}},"required":["id","kennelId","slug","title","eventType","startsAt","isPublic","lifecycleStatus"]}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"eventType":{"type":"string","minLength":1},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string","nullable":true,"maxLength":4000},"locationName":{"type":"string","nullable":true,"maxLength":200},"latitude":{"type":"number","nullable":true,"minimum":-90,"maximum":90},"longitude":{"type":"number","nullable":true,"minimum":-180,"maximum":180},"isPublic":{"type":"boolean"},"capacity":{"type":"integer","nullable":true,"minimum":0,"exclusiveMinimum":true},"hashCashCents":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/event-series":{"post":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"eventType":{"type":"string","minLength":1,"default":"trail"},"startsAt":{"type":"string","format":"date-time"},"count":{"type":"integer","minimum":1,"maximum":16,"default":8},"isPublic":{"type":"boolean"},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["title","startsAt"]}}}},"responses":{"201":{"description":"Weekly draft series created"},"403":{"description":"Forbidden"},"404":{"description":"Kennel not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/edit-access":{"get":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Whether the signed-in hare can edit this event"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/publish":{"post":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Published"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Already published or canceled"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/cancel":{"post":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Canceled"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/teaser":{"get":{"tags":["Events"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"SVG teaser image for a public event"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/registrations":{"post":{"tags":["Rego"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","minLength":1},"trailName":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"emergencyContact":{"type":"string"},"userId":{"type":"string","format":"uuid"},"waiverVersionId":{"type":"string","format":"uuid"},"waiverAccepted":{"type":"boolean"},"payableItemId":{"type":"string","format":"uuid"}},"required":["displayName"]}}}},"responses":{"201":{"description":"Registration created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"eventId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"guestRegistrationId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["going","maybe","cannot_go","waitlist"]},"paymentStatus":{"type":"string","enum":["unpaid","self_reported","confirmed","cash_at_trail","comped","waived","refund_reported","refunded"]},"checkedIn":{"type":"boolean"},"checkInQrPayload":{"type":"string"}},"required":["id","eventId","status","paymentStatus","checkedIn"]}}}},"400":{"description":"Registration closed or waiver required"},"403":{"description":"Members only"},"404":{"description":"Not found"},"409":{"description":"Tier is full"}}},"get":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Registration roster for check-in (On Sec)","content":{"application/json":{"schema":{"type":"object","properties":{"registrations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"trailName":{"type":"string"},"status":{"type":"string","enum":["going","maybe","cannot_go","waitlist"]},"paymentStatus":{"type":"string","enum":["unpaid","self_reported","confirmed","cash_at_trail","comped","waived","refund_reported","refunded"]},"checkedIn":{"type":"boolean"},"checkedOut":{"type":"boolean"}},"required":["id","displayName","status","paymentStatus","checkedIn"]}}},"required":["registrations"]}}}},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/registrations/me":{"get":{"tags":["Rego"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Signed-in user's registration for this trail"},"401":{"description":"Not signed in"},"404":{"description":"Not registered"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/rsvp":{"put":{"tags":["Rego"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["going","maybe","cannot_go"]}},"required":["status"]}}}},"responses":{"200":{"description":"RSVP saved. Trails do not require registration."},"400":{"description":"Not a trail, or the trail is not published"},"401":{"description":"Not signed in"},"403":{"description":"Not allowed"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/registrations/{registrationId}":{"patch":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["going","maybe","cannot_go","waitlist"]}},"required":["status"]}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Capacity full"}}}},"/api/v1/registrations/{registrationId}/payment/self-report":{"post":{"tags":["Rego"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reference":{"type":"string"}}}}}},"responses":{"200":{"description":"Payment self-reported"},"403":{"description":"Hash Cash is not open yet, or this is not your registration"},"404":{"description":"Not found"}}}},"/api/v1/registrations/{registrationId}/payment/confirm":{"post":{"tags":["Rego"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"method":{"type":"string","enum":["external","cash_at_trail","comp","waive"]}},"required":["method"]}}}},"responses":{"200":{"description":"Payment confirmed"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/registrations/{registrationId}/check-in":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"idempotencyKey":{"type":"string"}}}}}},"responses":{"200":{"description":"Checked in"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/registrations/{registrationId}/check-out":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"responses":{"200":{"description":"Checked out"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Not checked in"}}}},"/api/v1/registrations/{registrationId}/check-in-ticket":{"get":{"tags":["Rego"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"registrationId","in":"path"}],"responses":{"200":{"description":"QR payload for hasher check-in (§7.5)","content":{"application/json":{"schema":{"type":"object","properties":{"registrationId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"qrPayload":{"type":"string"}},"required":["registrationId","displayName","qrPayload"]}}}},"404":{"description":"Not found"}}}},"/api/v1/registrations/check-in/scan":{"post":{"tags":["Ops"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"qrPayload":{"type":"string","minLength":1},"idempotencyKey":{"type":"string"},"eventSlug":{"type":"string"}},"required":["qrPayload"]}}}},"responses":{"200":{"description":"Checked in from QR payload","content":{"application/json":{"schema":{"type":"object","properties":{"checkedIn":{"type":"boolean","enum":[true]},"runCount":{"type":"integer","minimum":0},"registrationId":{"type":"string","format":"uuid"},"displayName":{"type":"string"},"idempotent":{"type":"boolean"},"alreadyCheckedIn":{"type":"boolean"}},"required":["checkedIn","runCount"]}}}},"400":{"description":"Invalid payload"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Code belongs to a different trail"}}}},"/api/v1/kennels/{kennelSlug}/hash-cash/dashboard":{"get":{"tags":["Payments"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"},{"schema":{"type":"string","enum":["unpaid","self_reported","confirmed","cash_at_trail","comped","waived","refund_reported","refunded"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Hash Cash ledger and summary"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/payment-profile":{"patch":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nativeHandle":{"type":"string","maxLength":200},"refundLimitCents":{"type":"integer","minimum":0,"maximum":1000000}}}}}},"responses":{"200":{"description":"Payment profile updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/payments/{recordId}/refund":{"post":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"recordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["report","confirm"]},"note":{"type":"string","maxLength":500}},"required":["action"]}}}},"responses":{"200":{"description":"Refund status updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Illegal refund transition"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/tiers":{"post":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tierLabel":{"type":"string","minLength":1,"default":"Campout"},"tiers":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1},"amountCents":{"type":"integer","minimum":0},"capacity":{"type":"integer","minimum":0,"exclusiveMinimum":true}},"required":["title","amountCents","capacity"]},"minItems":1,"maxItems":12}},"required":["tiers"]}}}},"responses":{"201":{"description":"Campout tiers saved"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"get":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Payable tiers for an event"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/merch":{"post":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"amountCents":{"type":"integer","minimum":0},"sizes":{"type":"string"},"inventoryCount":{"type":"integer","minimum":0}},"required":["name","amountCents"]}}}},"responses":{"201":{"description":"Merch product created"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/merch/{productId}/orders":{"post":{"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"productId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"size":{"type":"string"},"quantity":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":20,"default":1}}}}}},"responses":{"201":{"description":"Merch order recorded"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hareline":{"get":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Upcoming hareline slots","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scheduledFor":{"type":"string","format":"date-time"},"locationStatus":{"type":"string"},"eventSlug":{"type":"string"},"hareUserId":{"type":"string","nullable":true,"format":"uuid"},"hareTrailName":{"type":"string"},"coHareUserId":{"type":"string","nullable":true,"format":"uuid"},"coHareTrailName":{"type":"string"},"eventTitle":{"type":"string"}},"required":["id","scheduledFor","locationStatus"]}}}}},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hareline/slots/{slotId}/claim":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"responses":{"200":{"description":"Hare claimed slot"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Already claimed"}}}},"/api/v1/kennels/{slug}/hareline/slots":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledFor":{"type":"array","items":{"type":"string","format":"date-time"},"minItems":1,"maxItems":52}},"required":["scheduledFor"]}}}},"responses":{"201":{"description":"Hareline dates added"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hareline/slots/{slotId}":{"delete":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"responses":{"200":{"description":"Hareline date removed"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Date has hares or trail details"}}}},"/api/v1/kennels/{slug}/hareline/slots/{slotId}/signup":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["hare","co_hare"],"default":"hare"}}}}}},"responses":{"200":{"description":"Signed up to hare"},"400":{"description":"Date has passed"},"403":{"description":"Kennel members only"},"404":{"description":"Not found"},"409":{"description":"Spot already taken"}}},"delete":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"responses":{"200":{"description":"Withdrawn from the date"},"403":{"description":"Forbidden"},"404":{"description":"Not on this date"}}}},"/api/v1/kennels/{slug}/hareline/me":{"get":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"What the signed-in user can do on this hareline","content":{"application/json":{"schema":{"type":"object","properties":{"isMember":{"type":"boolean"},"canManage":{"type":"boolean"}},"required":["isMember","canManage"]}}}},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hareline/slots/{slotId}/event":{"post":{"tags":["Ops"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"startsAt":{"type":"string","format":"date-time"},"description":{"type":"string","maxLength":4000},"locationName":{"type":"string","maxLength":200},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"localDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},"required":["title"]}}}},"responses":{"201":{"description":"Draft event created for the hareline date"},"403":{"description":"Only this date's hares (or hareline managers)"},"404":{"description":"Not found"},"409":{"description":"Date already has trail details"}}}},"/api/v1/kennels/{slug}/trail-defaults":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Kennel-level trail defaults (start time, hash cash, schedule)","content":{"application/json":{"schema":{"type":"object","properties":{"defaultStartTime":{"type":"string","nullable":true},"hashCashCents":{"type":"integer","nullable":true},"scheduleDescription":{"type":"string","nullable":true},"canEdit":{"type":"boolean"}},"required":["defaultStartTime","hashCashCents","scheduleDescription","canEdit"]}}}},"404":{"description":"Not found"}}},"patch":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"defaultStartTime":{"type":"string","nullable":true,"pattern":"^([01]\\d|2[0-3]):[0-5]\\d$"},"hashCashCents":{"type":"integer","nullable":true,"minimum":0,"maximum":100000},"scheduleDescription":{"type":"string","nullable":true,"maxLength":300}}}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"defaultStartTime":{"type":"string","nullable":true},"hashCashCents":{"type":"integer","nullable":true},"scheduleDescription":{"type":"string","nullable":true}},"required":["defaultStartTime","hashCashCents","scheduleDescription"]}}}},"403":{"description":"GM or MisMan only"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/editor":{"get":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Draft and published hub snapshots for editor","content":{"application/json":{"schema":{"type":"object","properties":{"draft":{"type":"object","properties":{"theme":{"type":"object","properties":{"presetId":{"type":"string","enum":["classic","bold","trail_night"],"default":"classic"},"tokenOverrides":{"type":"object","properties":{"accent":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"surface":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"headingFont":{"type":"string","enum":["system","rounded","condensed"]},"bodyFont":{"type":"string","enum":["system","rounded","condensed"]},"navStyle":{"type":"string","enum":["minimal","tabs","underline"]},"buttonStyle":{"type":"string","enum":["solid","outline","soft"]}},"default":{}}}},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1,"maxLength":80},"title":{"type":"string","minLength":1,"maxLength":200},"visibility":{"type":"string","enum":["public","member"],"default":"public"},"sortOrder":{"type":"integer","default":0},"isHome":{"type":"boolean","default":false},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string","minLength":1,"maxLength":64},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"],"default":"public"},"enabled":{"type":"boolean","default":true},"config":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"heading":{"type":"string"},"body":{"type":"string","maxLength":8000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","enum":["hero"]},"headline":{"type":"string","maxLength":200},"subhead":{"type":"string","maxLength":500}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["virgin_guide"]},"excerpt":{"type":"string","maxLength":2000},"ctaLabel":{"type":"string","maxLength":80}},"required":["type","excerpt"]},{"type":"object","properties":{"type":{"type":"string","enum":["faq"]},"items":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string","maxLength":300},"answer":{"type":"string","maxLength":2000}},"required":["question","answer"]},"maxItems":20}},"required":["type","items"]},{"type":"object","properties":{"type":{"type":"string","enum":["custom_cta"]},"label":{"type":"string","maxLength":80},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","label","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["map"]},"label":{"type":"string","maxLength":120},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"note":{"type":"string","maxLength":500}},"required":["type","label","latitude","longitude"]},{"type":"object","properties":{"type":{"type":"string","enum":["embed"]},"url":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","url"]},{"type":"object","properties":{"type":{"type":"string","enum":["contact"]},"heading":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":200,"format":"email"},"note":{"type":"string","maxLength":500}},"required":["type","email"]},{"type":"object","properties":{"type":{"type":"string","enum":["sponsor"]},"name":{"type":"string","maxLength":120},"href":{"type":"string","maxLength":500,"format":"uri"},"blurb":{"type":"string","maxLength":500}},"required":["type","name"]},{"type":"object","properties":{"type":{"type":"string","enum":["document"]},"title":{"type":"string","maxLength":200},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","title","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["passthrough"]}},"required":["type"]}]}},"required":["blockType","sortOrder"]},"default":[]}},"required":["slug","title"]},"minItems":1},"seo":{"type":"object","properties":{"title":{"type":"string","maxLength":70},"description":{"type":"string","maxLength":320},"ogImageUrl":{"type":"string","maxLength":500,"format":"uri"}}},"publishedAt":{"type":"string","format":"date-time"}},"required":["theme","pages"]},"published":{"type":"object","nullable":true,"properties":{"theme":{"type":"object","properties":{"presetId":{"type":"string","enum":["classic","bold","trail_night"],"default":"classic"},"tokenOverrides":{"type":"object","properties":{"accent":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"surface":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"headingFont":{"type":"string","enum":["system","rounded","condensed"]},"bodyFont":{"type":"string","enum":["system","rounded","condensed"]},"navStyle":{"type":"string","enum":["minimal","tabs","underline"]},"buttonStyle":{"type":"string","enum":["solid","outline","soft"]}},"default":{}}}},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1,"maxLength":80},"title":{"type":"string","minLength":1,"maxLength":200},"visibility":{"type":"string","enum":["public","member"],"default":"public"},"sortOrder":{"type":"integer","default":0},"isHome":{"type":"boolean","default":false},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string","minLength":1,"maxLength":64},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"],"default":"public"},"enabled":{"type":"boolean","default":true},"config":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"heading":{"type":"string"},"body":{"type":"string","maxLength":8000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","enum":["hero"]},"headline":{"type":"string","maxLength":200},"subhead":{"type":"string","maxLength":500}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["virgin_guide"]},"excerpt":{"type":"string","maxLength":2000},"ctaLabel":{"type":"string","maxLength":80}},"required":["type","excerpt"]},{"type":"object","properties":{"type":{"type":"string","enum":["faq"]},"items":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string","maxLength":300},"answer":{"type":"string","maxLength":2000}},"required":["question","answer"]},"maxItems":20}},"required":["type","items"]},{"type":"object","properties":{"type":{"type":"string","enum":["custom_cta"]},"label":{"type":"string","maxLength":80},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","label","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["map"]},"label":{"type":"string","maxLength":120},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"note":{"type":"string","maxLength":500}},"required":["type","label","latitude","longitude"]},{"type":"object","properties":{"type":{"type":"string","enum":["embed"]},"url":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","url"]},{"type":"object","properties":{"type":{"type":"string","enum":["contact"]},"heading":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":200,"format":"email"},"note":{"type":"string","maxLength":500}},"required":["type","email"]},{"type":"object","properties":{"type":{"type":"string","enum":["sponsor"]},"name":{"type":"string","maxLength":120},"href":{"type":"string","maxLength":500,"format":"uri"},"blurb":{"type":"string","maxLength":500}},"required":["type","name"]},{"type":"object","properties":{"type":{"type":"string","enum":["document"]},"title":{"type":"string","maxLength":200},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","title","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["passthrough"]}},"required":["type"]}]}},"required":["blockType","sortOrder"]},"default":[]}},"required":["slug","title"]},"minItems":1},"seo":{"type":"object","properties":{"title":{"type":"string","maxLength":70},"description":{"type":"string","maxLength":320},"ogImageUrl":{"type":"string","maxLength":500,"format":"uri"}}},"publishedAt":{"type":"string","format":"date-time"}},"required":["theme","pages"]}},"required":["draft","published"]}}}},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/draft":{"put":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"type":"object","properties":{"presetId":{"type":"string","enum":["classic","bold","trail_night"],"default":"classic"},"tokenOverrides":{"type":"object","properties":{"accent":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"surface":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"headingFont":{"type":"string","enum":["system","rounded","condensed"]},"bodyFont":{"type":"string","enum":["system","rounded","condensed"]},"navStyle":{"type":"string","enum":["minimal","tabs","underline"]},"buttonStyle":{"type":"string","enum":["solid","outline","soft"]}},"default":{}}}},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1,"maxLength":80},"title":{"type":"string","minLength":1,"maxLength":200},"visibility":{"type":"string","enum":["public","member"],"default":"public"},"sortOrder":{"type":"integer","default":0},"isHome":{"type":"boolean","default":false},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string","minLength":1,"maxLength":64},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"],"default":"public"},"enabled":{"type":"boolean","default":true},"config":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"heading":{"type":"string"},"body":{"type":"string","maxLength":8000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","enum":["hero"]},"headline":{"type":"string","maxLength":200},"subhead":{"type":"string","maxLength":500}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["virgin_guide"]},"excerpt":{"type":"string","maxLength":2000},"ctaLabel":{"type":"string","maxLength":80}},"required":["type","excerpt"]},{"type":"object","properties":{"type":{"type":"string","enum":["faq"]},"items":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string","maxLength":300},"answer":{"type":"string","maxLength":2000}},"required":["question","answer"]},"maxItems":20}},"required":["type","items"]},{"type":"object","properties":{"type":{"type":"string","enum":["custom_cta"]},"label":{"type":"string","maxLength":80},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","label","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["map"]},"label":{"type":"string","maxLength":120},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"note":{"type":"string","maxLength":500}},"required":["type","label","latitude","longitude"]},{"type":"object","properties":{"type":{"type":"string","enum":["embed"]},"url":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","url"]},{"type":"object","properties":{"type":{"type":"string","enum":["contact"]},"heading":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":200,"format":"email"},"note":{"type":"string","maxLength":500}},"required":["type","email"]},{"type":"object","properties":{"type":{"type":"string","enum":["sponsor"]},"name":{"type":"string","maxLength":120},"href":{"type":"string","maxLength":500,"format":"uri"},"blurb":{"type":"string","maxLength":500}},"required":["type","name"]},{"type":"object","properties":{"type":{"type":"string","enum":["document"]},"title":{"type":"string","maxLength":200},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","title","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["passthrough"]}},"required":["type"]}]}},"required":["blockType","sortOrder"]},"default":[]}},"required":["slug","title"]},"minItems":1},"seo":{"type":"object","properties":{"title":{"type":"string","maxLength":70},"description":{"type":"string","maxLength":320},"ogImageUrl":{"type":"string","maxLength":500,"format":"uri"}}},"publishedAt":{"type":"string","format":"date-time"}},"required":["theme","pages"]}}}},"responses":{"200":{"description":"Saved draft","content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"type":"object","properties":{"presetId":{"type":"string","enum":["classic","bold","trail_night"],"default":"classic"},"tokenOverrides":{"type":"object","properties":{"accent":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"surface":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$"},"headingFont":{"type":"string","enum":["system","rounded","condensed"]},"bodyFont":{"type":"string","enum":["system","rounded","condensed"]},"navStyle":{"type":"string","enum":["minimal","tabs","underline"]},"buttonStyle":{"type":"string","enum":["solid","outline","soft"]}},"default":{}}}},"pages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":1,"maxLength":80},"title":{"type":"string","minLength":1,"maxLength":200},"visibility":{"type":"string","enum":["public","member"],"default":"public"},"sortOrder":{"type":"integer","default":0},"isHome":{"type":"boolean","default":false},"blocks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"blockType":{"type":"string","minLength":1,"maxLength":64},"sortOrder":{"type":"integer"},"visibility":{"type":"string","enum":["public","logged_in","member","misman"],"default":"public"},"enabled":{"type":"boolean","default":true},"config":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"heading":{"type":"string"},"body":{"type":"string","maxLength":8000}},"required":["type","body"]},{"type":"object","properties":{"type":{"type":"string","enum":["hero"]},"headline":{"type":"string","maxLength":200},"subhead":{"type":"string","maxLength":500}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["virgin_guide"]},"excerpt":{"type":"string","maxLength":2000},"ctaLabel":{"type":"string","maxLength":80}},"required":["type","excerpt"]},{"type":"object","properties":{"type":{"type":"string","enum":["faq"]},"items":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string","maxLength":300},"answer":{"type":"string","maxLength":2000}},"required":["question","answer"]},"maxItems":20}},"required":["type","items"]},{"type":"object","properties":{"type":{"type":"string","enum":["custom_cta"]},"label":{"type":"string","maxLength":80},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","label","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["map"]},"label":{"type":"string","maxLength":120},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"note":{"type":"string","maxLength":500}},"required":["type","label","latitude","longitude"]},{"type":"object","properties":{"type":{"type":"string","enum":["embed"]},"url":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","url"]},{"type":"object","properties":{"type":{"type":"string","enum":["contact"]},"heading":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":200,"format":"email"},"note":{"type":"string","maxLength":500}},"required":["type","email"]},{"type":"object","properties":{"type":{"type":"string","enum":["sponsor"]},"name":{"type":"string","maxLength":120},"href":{"type":"string","maxLength":500,"format":"uri"},"blurb":{"type":"string","maxLength":500}},"required":["type","name"]},{"type":"object","properties":{"type":{"type":"string","enum":["document"]},"title":{"type":"string","maxLength":200},"href":{"type":"string","maxLength":500,"format":"uri"}},"required":["type","title","href"]},{"type":"object","properties":{"type":{"type":"string","enum":["passthrough"]}},"required":["type"]}]}},"required":["blockType","sortOrder"]},"default":[]}},"required":["slug","title"]},"minItems":1},"seo":{"type":"object","properties":{"title":{"type":"string","maxLength":70},"description":{"type":"string","maxLength":320},"ogImageUrl":{"type":"string","maxLength":500,"format":"uri"}}},"publishedAt":{"type":"string","format":"date-time"}},"required":["theme","pages"]}}}},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{slug}/hub/publish":{"post":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Published hub revision","content":{"application/json":{"schema":{"type":"object","properties":{"revisionId":{"type":"string","format":"uuid"},"publishedAt":{"type":"string"}},"required":["revisionId","publishedAt"]}}}},"400":{"description":"Validation failed"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{slug}/hub/domain":{"put":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string","minLength":3,"maxLength":253,"pattern":"^[a-z0-9.-]+$"},"verify":{"type":"boolean"}},"required":["hostname"]}}}},"responses":{"200":{"description":"Custom domain configured","content":{"application/json":{"schema":{"type":"object","properties":{"customDomain":{"type":"string"},"verified":{"type":"boolean"},"dnsHint":{"type":"string"}},"required":["customDomain","verified","dnsHint"]}}}},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"get":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Custom domain diagnostic"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/domain/verify":{"post":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"DNS TXT check result"},"400":{"description":"No domain saved"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/rollback":{"post":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"target":{"type":"string","enum":["published","previous"]}},"required":["target"]}}}},"responses":{"200":{"description":"Draft restored"},"400":{"description":"Nothing to restore"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/contact":{"post":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"email":{"type":"string","maxLength":200,"format":"email"},"body":{"type":"string","minLength":1,"maxLength":2000}},"required":["name","email","body"]}}}},"responses":{"201":{"description":"Message sent to the kennel"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hub/analytics":{"get":{"tags":["HubBuilder"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Hub page view summary (Rope Top)"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/trails":{"get":{"tags":["Trails"],"responses":{"200":{"description":"Trails the signed-in user has hared or is scheduled to hare","content":{"application/json":{"schema":{"type":"object","properties":{"trails":{"type":"array","items":{"type":"object","properties":{"slotId":{"type":"string","format":"uuid"},"kennelSlug":{"type":"string"},"kennelName":{"type":"string"},"eventSlug":{"type":"string","nullable":true},"title":{"type":"string"},"scheduledFor":{"type":"string","format":"date-time"},"role":{"type":"string","enum":["hare","co_hare"]},"status":{"type":"string","enum":["hared","scheduled"]},"plotted":{"type":"boolean"},"needsPlotting":{"type":"boolean"},"locationStatus":{"type":"string"},"hareChatId":{"type":"string","nullable":true,"format":"uuid"},"kennelHashCashCents":{"type":"integer","nullable":true},"kennelDefaultStartTime":{"type":"string","nullable":true},"event":{"type":"object","nullable":true,"properties":{"title":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"lifecycleStatus":{"type":"string"},"description":{"type":"string","nullable":true},"locationName":{"type":"string","nullable":true},"latitude":{"type":"number","nullable":true},"longitude":{"type":"number","nullable":true},"hashCashCents":{"type":"string","nullable":true}},"required":["title","startsAt","lifecycleStatus","description","locationName","latitude","longitude","hashCashCents"]}},"required":["slotId","kennelSlug","kennelName","eventSlug","title","scheduledFor","role","status","plotted","needsPlotting","locationStatus","hareChatId","kennelHashCashCents","kennelDefaultStartTime","event"]}}},"required":["trails"]}}}},"403":{"description":"Authentication required"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/trail/workspace":{"get":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Hare private trail workspace"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"patch":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceNotes":{"type":"string"},"scoutNotes":{"type":"string"},"revealAt":{"type":"string","nullable":true,"format":"date-time"}}}}}},"responses":{"200":{"description":"Workspace saved"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/debrief":{"post":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"notes":{"type":"string","minLength":1}},"required":["notes"]}}}},"responses":{"200":{"description":"Debrief saved to trail intelligence"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/trail-intelligence":{"get":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"q","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":24},"required":false,"name":"withinMonths","in":"query"}],"responses":{"200":{"description":"Matching trail intelligence records"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/trail/gpx":{"get":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Trail GPX export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"put":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"gpxData":{"type":"string","minLength":10}},"required":["gpxData"]}}}},"responses":{"200":{"description":"GPX saved"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/trail/map-source":{"post":{"tags":["Trails"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri"}},"required":["url"]}}}},"responses":{"200":{"description":"Resolved KML from a linked map URL"},"400":{"description":"Bad request"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/feed":{"get":{"tags":["Social"],"responses":{"200":{"description":"Posts from joined and followed kennels"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{kennelSlug}/feed":{"get":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":50},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","enum":["announcement","discussion","photo","poll","volunteer","event_discussion"]},"required":false,"name":"postType","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"eventId","in":"query"}],"responses":{"200":{"description":"Kennel feed posts"},"404":{"description":"Not found"}}},"post":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1},"postType":{"type":"string","enum":["announcement","discussion","photo","poll","volunteer","event_discussion"],"default":"discussion"},"pinned":{"type":"boolean"},"eventId":{"type":"string","format":"uuid"},"poll":{"type":"object","properties":{"question":{"type":"string","minLength":1},"options":{"type":"array","items":{"type":"string","minLength":1},"minItems":2,"maxItems":6}},"required":["question","options"]}},"required":["content"]}}}},"responses":{"201":{"description":"Post created"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/feed/{postId}":{"patch":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean"}},"required":["pinned"]}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/feed/{postId}/comments":{"get":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"}],"responses":{"200":{"description":"Comments"},"404":{"description":"Not found"}}},"post":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","minLength":1}},"required":["content"]}}}},"responses":{"201":{"description":"Comment created"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/feed/{postId}/poll-vote":{"post":{"tags":["Social"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"optionIndex":{"type":"integer","minimum":0}},"required":["optionIndex"]}}}},"responses":{"200":{"description":"Vote recorded"},"400":{"description":"Invalid poll"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/role-definitions":{"get":{"tags":["MisMan"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Custom MisMan display titles"},"404":{"description":"Not found"}}},"put":{"tags":["MisMan"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"roles":{"type":"array","items":{"type":"object","properties":{"roleKey":{"type":"string"},"displayTitle":{"type":"string","minLength":1},"sortOrder":{"type":"integer"}},"required":["roleKey","displayTitle"]}}},"required":["roles"]}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/board/posts":{"get":{"tags":["Community"],"parameters":[{"schema":{"type":"string"},"required":false,"name":"category","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Global message board posts"}}}},"/api/v1/discover/visitor":{"get":{"tags":["Travel"],"parameters":[{"schema":{"type":"number","nullable":true},"required":false,"name":"lat","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"lng","in":"query"},{"schema":{"type":"number","nullable":true},"required":false,"name":"radiusKm","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"to","in":"query"}],"responses":{"200":{"description":"Visitor-oriented discovery"}}}},"/api/v1/travel/itineraries":{"post":{"tags":["Travel"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1},"destinationLabel":{"type":"string"},"lat":{"type":"number"},"lng":{"type":"number"},"radiusKm":{"type":"number"},"startsAt":{"type":"string","format":"date-time"},"endsAt":{"type":"string","format":"date-time"},"stops":{"type":"array","items":{"type":"object","properties":{"kennelSlug":{"type":"string"},"eventSlug":{"type":"string"},"notes":{"type":"string"}},"required":["kennelSlug"]}}},"required":["title"]}}}},"responses":{"201":{"description":"Itinerary created"}}},"get":{"tags":["Travel"],"responses":{"200":{"description":"Itineraries for authenticated user"},"403":{"description":"Authentication required"}}}},"/api/v1/travel/itineraries/{itineraryId}":{"get":{"tags":["Travel"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"itineraryId","in":"path"}],"responses":{"200":{"description":"Itinerary detail"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/rideshare":{"get":{"tags":["Travel"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Rideshare offers and requests"},"404":{"description":"Not found"}}},"post":{"tags":["Travel"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"offerType":{"type":"string","enum":["offer","need"]},"pickupRegion":{"type":"string","minLength":2,"maxLength":200},"seats":{"type":"integer","minimum":1,"maximum":8,"default":1},"eventSlug":{"type":"string"},"departureAt":{"type":"string","format":"date-time"},"notes":{"type":"string","maxLength":500},"costSharePreference":{"type":"string","maxLength":120},"contactPreference":{"type":"string","enum":["kennel_feed","in_app","email"]},"membersOnly":{"type":"boolean"}},"required":["offerType","pickupRegion"]}}}},"responses":{"201":{"description":"Created"},"403":{"description":"Authentication required"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/rideshare/matches":{"get":{"tags":["Travel"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Suggested offer/request pairs"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/rideshare/{offerId}/interest":{"post":{"tags":["Travel"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"offerId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","maxLength":500}}}}}},"responses":{"201":{"description":"Interest recorded (messaging hook)"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/safety-networks":{"get":{"tags":["Safety"],"responses":{"200":{"description":"Opt-in regional safety networks (public policy only)"}}}},"/api/v1/kennels/{kennelSlug}/incidents":{"post":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","enum":["safety_on_trail","harassment","assault","threats","discrimination","financial_misconduct","property_damage","medical","rule_violation","other"]},"summary":{"type":"string","minLength":10,"maxLength":4000}},"required":["category","summary"]}}}},"responses":{"201":{"description":"Incident report filed"},"403":{"description":"Authentication required"},"404":{"description":"Not found"}}},"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Incident queue (safety roles)"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/incidents/{incidentId}":{"patch":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"incidentId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["received","reviewing","action_taken","closed"]},"confidentialNotes":{"type":"string","maxLength":8000},"evidenceRefs":{"type":"string","maxLength":4000}}}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/incidents/export":{"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Authorized incident export"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{kennelSlug}/safety-networks":{"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Networks this kennel joined"},"404":{"description":"Not found"}}}},"/api/v1/platform/safety/urgent-restrictions":{"get":{"tags":["Safety"],"responses":{"200":{"description":"Active platform urgent restrictions (operators)"}}},"post":{"tags":["Safety"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subjectUserId":{"type":"string","format":"uuid"},"summary":{"type":"string","minLength":20,"maxLength":2000}},"required":["subjectUserId","summary"]}}}},"responses":{"201":{"description":"Created"},"403":{"description":"Forbidden"}}}},"/api/v1/platform/safety/urgent-restrictions/{restrictionId}/lift":{"post":{"tags":["Safety"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"restrictionId","in":"path"}],"responses":{"200":{"description":"Lifted"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/urgent-restriction":{"get":{"tags":["Safety"],"responses":{"200":{"description":"The signed-in user's active platform restriction, if any"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/urgent-restriction/appeal":{"post":{"tags":["Safety"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"statement":{"type":"string","minLength":20,"maxLength":4000}},"required":["statement"]}}}},"responses":{"200":{"description":"Appeal submitted"},"401":{"description":"Not signed in"},"404":{"description":"No active restriction"},"409":{"description":"Appeal already filed"}}}},"/api/v1/platform/safety/urgent-restrictions/{restrictionId}/appeal/decide":{"post":{"tags":["Safety"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"restrictionId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["upheld","lifted"]},"note":{"type":"string","maxLength":2000}},"required":["decision"]}}}},"responses":{"200":{"description":"Appeal decided"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"No submitted appeal"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/safety-debrief":{"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Event safety debrief"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"patch":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"weatherNote":{"type":"string","nullable":true,"maxLength":2000},"hazardNote":{"type":"string","nullable":true,"maxLength":2000},"waypointLabel":{"type":"string","nullable":true,"maxLength":200},"waypointLatitude":{"type":"number","nullable":true,"minimum":-90,"maximum":90},"waypointLongitude":{"type":"number","nullable":true,"minimum":-180,"maximum":180},"debrief":{"type":"string","nullable":true,"maxLength":4000}}}}}},"responses":{"200":{"description":"Saved"},"400":{"description":"Invalid waypoint"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/ban-list":{"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Kennel ban/restriction records"},"403":{"description":"Forbidden"}}},"post":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subjectUserId":{"type":"string","format":"uuid"},"restrictionType":{"type":"string","enum":["kennel_ban","warning","temporary_event","temporary_community","removal","event_exclusion","conditional_return","event_restriction","temporary"],"default":"kennel_ban"},"reason":{"type":"string","minLength":10,"maxLength":4000},"reasonCategory":{"type":"string","enum":["safety_on_trail","harassment","assault","threats","discrimination","financial_misconduct","property_damage","conduct","other"],"default":"other"},"internalNotes":{"type":"string","maxLength":4000},"eventId":{"type":"string","format":"uuid"},"effectiveUntil":{"type":"string","format":"date-time"},"shareToSafetyNetwork":{"type":"boolean"},"networkSlug":{"type":"string"},"alertType":{"type":"string","enum":["contact_before_access","do_not_admit","restricted_until"]}},"required":["subjectUserId","reason"]}}}},"responses":{"201":{"description":"Created"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{kennelSlug}/ban-list/{recordId}":{"patch":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"recordId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["lifted"]},"appealStatus":{"type":"string","enum":["none","requested","under_review","denied","upheld"]}}}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{kennelSlug}/safety-network-alerts":{"get":{"tags":["Safety"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Cross-kennel alerts for joined networks"}}}},"/api/v1/kennels/{kennelSlug}/feed/{postId}/report":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":5,"maxLength":500}},"required":["reason"]}}}},"responses":{"201":{"description":"Report queued"},"403":{"description":"Authentication required"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/moderation/queue":{"get":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","enum":["open","resolved"]},"required":false,"name":"status","in":"query"}],"responses":{"200":{"description":"Moderation queue"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/moderation/queue/{reportId}/resolve":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"reportId","in":"path"}],"responses":{"200":{"description":"Resolved"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/moderation/queue/{reportId}/act":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"reportId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["resolve","hide","warn","restrict_posting","escalate","lock_comments","remove_member"]},"note":{"type":"string","maxLength":2000},"restrictUntil":{"type":"string","format":"date-time"}},"required":["action"]}}}},"responses":{"200":{"description":"Action applied"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/feed/{postId}/comments/{commentId}/report":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"postId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"commentId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","minLength":5,"maxLength":500}},"required":["reason"]}}}},"responses":{"201":{"description":"Comment report queued"},"403":{"description":"Authentication required"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/moderation/reports":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"targetType":{"type":"string","enum":["profile","photo"]},"subjectUserId":{"type":"string","format":"uuid"},"mediaAssetId":{"type":"string","format":"uuid"},"reason":{"type":"string","minLength":5,"maxLength":500}},"required":["targetType","reason"]}}}},"responses":{"201":{"description":"Report queued"},"403":{"description":"Authentication required"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/moderation/posting-restrictions":{"get":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Active posting restrictions"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{kennelSlug}/moderation/posting-restrictions/{restrictionId}/lift":{"post":{"tags":["Moderation"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"restrictionId","in":"path"}],"responses":{"200":{"description":"Lifted"},"403":{"description":"Forbidden"}}}},"/api/v1/kennels/{kennelSlug}/audit-log":{"get":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Recent audit entries for kennel-scoped actions"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/analytics/overview":{"get":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Kennel-level operational counts"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/successions":{"get":{"tags":["Governance"],"responses":{"200":{"description":"Open GM handoffs for the signed-in hasher"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{kennelSlug}/succession":{"get":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Open GM handoff, if any"},"401":{"description":"Not signed in"},"403":{"description":"Forbidden"},"404":{"description":"Kennel not found"}}},"post":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"201":{"description":"Handoff started"},"400":{"description":"Invalid handoff"},"401":{"description":"Not signed in"},"403":{"description":"GM required"},"404":{"description":"Kennel or hasher not found"},"409":{"description":"A handoff is already open"}}}},"/api/v1/kennels/{kennelSlug}/succession/accept":{"post":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Handoff accepted"},"401":{"description":"Not signed in"},"403":{"description":"Not the incoming GM"},"404":{"description":"No open handoff"}}}},"/api/v1/kennels/{kennelSlug}/succession/schedule":{"post":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"immediate":{"type":"boolean"},"effectiveAt":{"type":"string","format":"date-time"},"outgoingRole":{"type":"string"},"announce":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Handoff scheduled or completed"},"400":{"description":"Invalid schedule"},"401":{"description":"Not signed in"},"403":{"description":"Only the outgoing GM"},"404":{"description":"No accepted handoff"}}}},"/api/v1/kennels/{kennelSlug}/succession/cancel":{"post":{"tags":["Governance"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Handoff cancelled"},"401":{"description":"Not signed in"},"403":{"description":"Forbidden"},"404":{"description":"No open handoff"}}}},"/api/v1/kennels/{kennelSlug}/invites":{"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"approvalRequired":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Invite link created"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Kennel not found"}}},"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Active invite links"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Kennel not found"}}}},"/api/v1/kennels/{kennelSlug}/invite-policy":{"patch":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"approvalRequired":{"type":"boolean"}},"required":["approvalRequired"]}}}},"responses":{"200":{"description":"Kennel invite approval policy saved"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Kennel not found"}}}},"/api/v1/kennels/{kennelSlug}/invites/{inviteId}/revoke":{"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"inviteId","in":"path"}],"responses":{"200":{"description":"Invite revoked"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Invite not found"}}}},"/api/v1/join/{token}":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string","minLength":8},"required":true,"name":"token","in":"path"}],"responses":{"200":{"description":"Invite preview"},"404":{"description":"Invite not found"}}},"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string","minLength":8},"required":true,"name":"token","in":"path"}],"responses":{"200":{"description":"Already a member or waiting for approval"},"201":{"description":"Joined or requested"},"401":{"description":"Not signed in"},"403":{"description":"Restricted"},"404":{"description":"Invite not found"}}}},"/api/v1/kennels/{kennelSlug}/join-requests":{"get":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Hashers waiting for approval"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Kennel not found"}}}},"/api/v1/kennels/{kennelSlug}/join-requests/{memberId}/{decision}":{"post":{"tags":["Kennels"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"memberId","in":"path"},{"schema":{"type":"string","enum":["approve","decline"]},"required":true,"name":"decision","in":"path"}],"responses":{"200":{"description":"Request reviewed"},"401":{"description":"Not signed in"},"403":{"description":"GM or MisMan required"},"404":{"description":"Request not found"}}}},"/api/v1/public/web-push":{"get":{"tags":["Public"],"responses":{"200":{"description":"VAPID public key for browser push"}}}},"/api/v1/public/developer":{"get":{"tags":["Public"],"responses":{"200":{"description":"Public integration metadata"}}}},"/api/v1/locales/{locale}":{"get":{"tags":["Public"],"parameters":[{"schema":{"type":"string","enum":["en","es"]},"required":true,"name":"locale","in":"path"}],"responses":{"200":{"description":"UI string bundle"},"404":{"description":"Unsupported locale"}}}},"/api/v1/kennels/{kennelSlug}/waiver/current":{"get":{"tags":["Rego"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Effective waiver for registration"},"404":{"description":"Kennel or waiver not found"}}}},"/api/v1/kennels/{kennelSlug}/role-assignments":{"get":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Active role assignments"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"post":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$"}},"required":["role"]}}}},"responses":{"201":{"description":"Role assigned"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/role-assignments/{assignmentId}/revoke":{"post":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"assignmentId","in":"path"}],"responses":{"200":{"description":"Revoked"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/settings":{"patch":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"isPublic":{"type":"boolean"},"name":{"type":"string","minLength":1},"tagline":{"type":"string"}}}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/roles":{"post":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"displayTitle":{"type":"string","minLength":2,"maxLength":80},"groups":{"type":"array","items":{"type":"string"},"maxItems":7}},"required":["displayTitle","groups"]}}}},"responses":{"201":{"description":"Rank created"},"400":{"description":"Invalid rank"},"403":{"description":"Forbidden"},"404":{"description":"Not found"},"409":{"description":"Rank already exists"},"500":{"description":"Could not create rank"}}}},"/api/v1/kennels/{kennelSlug}/roles/{roleKey}":{"patch":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$"},"required":true,"name":"roleKey","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"displayTitle":{"type":"string","minLength":2,"maxLength":80},"groups":{"type":"array","items":{"type":"string"},"maxItems":7}}}}}},"responses":{"200":{"description":"Rank updated"},"400":{"description":"Invalid rank"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"delete":{"tags":["RBAC"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,39}$"},"required":true,"name":"roleKey","in":"path"}],"responses":{"200":{"description":"Rank removed"},"400":{"description":"Built-in rank"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/media":{"post":{"tags":["Media"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"caption":{"type":"string","maxLength":500},"eventSlug":{"type":"string"},"album":{"type":"string","enum":["public","private"]}},"required":["url"]}}}},"responses":{"201":{"description":"Media asset recorded"},"403":{"description":"Hash Flash only"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/media/{mediaId}/tags":{"get":{"tags":["Media"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mediaId","in":"path"}],"responses":{"200":{"description":"Approved photo tags. Pending tags are visible to the tagger and the tagged hasher."},"404":{"description":"Not found"}}},"post":{"tags":["Media"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"mediaId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"}},"required":["userId"]}}}},"responses":{"201":{"description":"Tag waiting for the hasher's approval"},"403":{"description":"Hash Flash only"},"404":{"description":"Not found"},"409":{"description":"Already approved"}}}},"/api/v1/users/me/photo-tags":{"get":{"tags":["Media"],"responses":{"200":{"description":"Photo tags waiting for the signed-in hasher"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/photo-tags/{tagId}/approve":{"post":{"tags":["Media"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"tagId","in":"path"}],"responses":{"200":{"description":"Tag approved and now public"},"401":{"description":"Not signed in"},"404":{"description":"Not found"},"409":{"description":"Already decided"}}}},"/api/v1/users/me/photo-tags/{tagId}/decline":{"post":{"tags":["Media"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"tagId","in":"path"}],"responses":{"200":{"description":"Tag declined"},"401":{"description":"Not signed in"},"404":{"description":"Not found"},"409":{"description":"Already decided"}}}},"/api/v1/users/me/notification-preferences":{"get":{"tags":["Notifications"],"responses":{"200":{"description":"Notification preferences"},"401":{"description":"Not signed in"}}},"patch":{"tags":["Notifications"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"emailEnabled":{"type":"boolean"},"pushEnabled":{"type":"boolean"},"inAppEnabled":{"type":"boolean"},"delivery":{"type":"string","enum":["immediate","daily","weekly"]},"quietHoursStart":{"type":"string","nullable":true,"pattern":"^\\d{2}:\\d{2}$"},"quietHoursEnd":{"type":"string","nullable":true,"pattern":"^\\d{2}:\\d{2}$"},"eventAlerts":{"type":"boolean"},"globalBoardSubscribed":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/notifications":{"get":{"tags":["Notifications"],"responses":{"200":{"description":"In-app inbox"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/notifications/{notificationId}/read":{"post":{"tags":["Notifications"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"notificationId","in":"path"}],"responses":{"200":{"description":"Marked read"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/push-tokens":{"post":{"tags":["Notifications"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"platform":{"type":"string","enum":["expo","web"]},"token":{"type":"string","minLength":4,"maxLength":4000}},"required":["platform","token"]}}}},"responses":{"200":{"description":"Already registered"},"201":{"description":"Registered"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/notifications/digest/flush":{"post":{"tags":["Notifications"],"responses":{"200":{"description":"Digest delivered"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{kennelSlug}/events/{eventSlug}/reports":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"eventSlug","in":"path"}],"responses":{"200":{"description":"Event registration and payment report"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/registrations":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/attendance":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/payments":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/payments.pdf":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"PDF payment report"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/members":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/audit":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/hareline":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/trails":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/exports/waivers":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string"},"required":false,"name":"eventSlug","in":"query"}],"responses":{"200":{"description":"CSV export"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/imports/members":{"post":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":200000}},"required":["csv"]}}}},"responses":{"200":{"description":"Import result"},"400":{"description":"Invalid CSV"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/imports/events":{"post":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":200000}},"required":["csv"]}}}},"responses":{"200":{"description":"Event import result"},"400":{"description":"Invalid CSV"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/imports/calendar":{"post":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ics":{"type":"string","minLength":1,"maxLength":200000}},"required":["ics"]}}}},"responses":{"200":{"description":"Calendar import result"},"400":{"description":"Invalid calendar"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/imports/financial-history":{"post":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string","minLength":1,"maxLength":200000}},"required":["csv"]}}}},"responses":{"200":{"description":"Historical payment status import"},"400":{"description":"Invalid CSV"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/imports/photos":{"post":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"eventSlug":{"type":"string"},"photos":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000},"caption":{"type":"string","maxLength":500},"album":{"type":"string","enum":["public","private"]}},"required":["url"]},"minItems":1,"maxItems":40}},"required":["photos"]}}}},"responses":{"200":{"description":"Bulk photo import result"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{kennelSlug}/migration":{"get":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"responses":{"200":{"description":"Facebook and website migration copy"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}},"patch":{"tags":["Reporting"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"facebookGroupUrl":{"type":"string","nullable":true,"maxLength":500}},"required":["facebookGroupUrl"]}}}},"responses":{"200":{"description":"Updated"},"400":{"description":"Invalid URL"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/passport":{"get":{"tags":["Passport"],"responses":{"200":{"description":"Personal hash passport"},"401":{"description":"Not signed in"}}}},"/api/v1/users/{userId}/passport":{"get":{"tags":["Passport"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"responses":{"200":{"description":"Public passport"},"404":{"description":"Hidden or missing"}}}},"/api/v1/users/me/subscription":{"get":{"tags":["Passport"],"responses":{"200":{"description":"TrueTrail subscription"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/subscription/checkout":{"post":{"tags":["Passport"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"plan":{"type":"string","enum":["base","premium"]}},"required":["plan"]}}}},"responses":{"200":{"description":"Checkout session or unconfigured"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/subscription/receipt":{"post":{"tags":["Passport"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","enum":["apple","google"]},"receipt":{"type":"string","minLength":4,"maxLength":200000}},"required":["provider","receipt"]}}}},"responses":{"200":{"description":"Receipt stored"},"202":{"description":"Pending live verification"},"401":{"description":"Not signed in"}}}},"/api/v1/users/me/tos":{"post":{"tags":["Passport"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"accepted":{"type":"boolean","enum":[true]}},"required":["accepted"]}}}},"responses":{"200":{"description":"Accepted"},"401":{"description":"Not signed in"}}}},"/api/v1/kennels/{kennelSlug}/members/{userId}/run-count":{"patch":{"tags":["Passport"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"kennelSlug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"runCount":{"type":"integer","minimum":0,"maximum":100000},"reason":{"type":"string","minLength":3,"maxLength":500}},"required":["runCount","reason"]}}}},"responses":{"200":{"description":"Updated"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}}}},"/api/v1/users/me/passport/wrapped":{"get":{"tags":["Passport"],"parameters":[{"schema":{"type":"integer","minimum":2000,"maximum":2100},"required":false,"name":"year","in":"query"}],"responses":{"200":{"description":"Annual Hash Wrapped recap"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}}},"/api/v1/users/me/passport/cv":{"get":{"tags":["Passport"],"responses":{"200":{"description":"Hash CV PDF"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}}},"/api/v1/users/me/offline-maps":{"get":{"tags":["Passport"],"responses":{"200":{"description":"Saved offline map pins"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}},"post":{"tags":["Passport"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120},"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"kennelSlug":{"type":"string"}},"required":["label","latitude","longitude"]}}}},"responses":{"201":{"description":"Map pin saved"},"400":{"description":"Too many pins"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}}},"/api/v1/users/me/travel/bucket":{"get":{"tags":["Travel"],"responses":{"200":{"description":"Hash bucket list"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}},"post":{"tags":["Travel"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":120},"country":{"type":"string","maxLength":80},"kennelSlug":{"type":"string"}},"required":["label"]}}}},"responses":{"201":{"description":"Bucket item added"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}}},"/api/v1/users/me/travel/bucket/{itemId}/done":{"post":{"tags":["Travel"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"itemId","in":"path"}],"responses":{"200":{"description":"Marked visited"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"},"404":{"description":"Not found"}}}},"/api/v1/users/me/travel/alerts":{"get":{"tags":["Travel"],"responses":{"200":{"description":"Events on premium trip dates"},"401":{"description":"Not signed in"},"403":{"description":"Premium subscription required"}}}},"/api/v1/users/me/conversations":{"get":{"tags":["Messages"],"responses":{"200":{"description":"Conversations with last message and unread count, newest first"},"401":{"description":"Sign in required"}}}},"/api/v1/users/me/conversations/unread":{"get":{"tags":["Messages"],"responses":{"200":{"description":"Unread totals for the nav badge (muted threads excluded)","content":{"application/json":{"schema":{"type":"object","properties":{"unreadConversations":{"type":"integer"},"unreadMessages":{"type":"number"}},"required":["unreadConversations","unreadMessages"]}}}},"401":{"description":"Sign in required"}}}},"/api/v1/users/me/message-contacts":{"get":{"tags":["Messages"],"responses":{"200":{"description":"Kennel-mates the user can message"},"401":{"description":"Sign in required"}}}},"/api/v1/conversations":{"post":{"tags":["Messages"],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["direct"]},"userId":{"type":"string","format":"uuid"}},"required":["type","userId"]},{"type":"object","properties":{"type":{"type":"string","enum":["group"]},"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50},"title":{"type":"string","maxLength":80}},"required":["type","userIds"]}]}}}},"responses":{"200":{"description":"Existing direct conversation"},"201":{"description":"Conversation created"},"400":{"description":"Invalid members"},"401":{"description":"Sign in required"},"403":{"description":"You can only message kennel-mates"}}}},"/api/v1/conversations/{conversationId}":{"get":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Conversation with members and read positions"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}},"patch":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","nullable":true,"maxLength":80}},"required":["title"]}}}},"responses":{"200":{"description":"Renamed"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"},"409":{"description":"This conversation can't be renamed"}}}},"/api/v1/conversations/{conversationId}/mute":{"put":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"muted":{"type":"boolean"}},"required":["muted"]}}}},"responses":{"200":{"description":"Mute updated"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/members":{"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"userIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50}},"required":["userIds"]}}}},"responses":{"200":{"description":"Members added"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"},"409":{"description":"Members can't be changed here"}}}},"/api/v1/conversations/{conversationId}/members/{userId}":{"delete":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"responses":{"200":{"description":"Member removed (or you left)"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"},"409":{"description":"Members can't be changed here"}}}},"/api/v1/conversations/{conversationId}/leave":{"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Left the group"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"},"409":{"description":"You can't leave this conversation"}}}},"/api/v1/conversations/{conversationId}/messages":{"get":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"before","in":"query"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"since","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":30},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Messages (oldest first) plus typing and read positions"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}},"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","maxLength":4000,"default":""},"replyToMessageId":{"type":"string","format":"uuid"},"gifId":{"type":"string","maxLength":64},"photos":{"type":"array","items":{"type":"object","properties":{"dataUrl":{"type":"string","maxLength":2100000},"width":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":10000},"height":{"type":"integer","minimum":0,"exclusiveMinimum":true,"maximum":10000}},"required":["dataUrl"]},"maxItems":4}}}}}},"responses":{"201":{"description":"Message sent"},"400":{"description":"Invalid photo, GIF or reply"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/messages/{messageId}":{"patch":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"messageId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":4000}},"required":["body"]}}}},"responses":{"200":{"description":"Edited"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}},"delete":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"messageId","in":"path"}],"responses":{"200":{"description":"Deleted (unsent)"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/read":{"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"responses":{"200":{"description":"Marked read"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/typing":{"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"typing":{"type":"boolean","default":true}}}}}},"responses":{"200":{"description":"Typing state set"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/kennels/{slug}/hareline/slots/{slotId}/hare-chat":{"post":{"tags":["Messages"],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"slotId","in":"path"}],"responses":{"200":{"description":"The slot's hare chat (created if missing)"},"401":{"description":"Sign in required"},"403":{"description":"Only this date's hares (or hareline managers)"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/messages/{messageId}/reaction":{"put":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"messageId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string","minLength":1,"maxLength":32,"pattern":"^(?:\\p{Extended_Pictographic}|\\p{Regional_Indicator})(?:\\p{Extended_Pictographic}|\\p{Emoji_Modifier}|\\p{Regional_Indicator}|\\u200d|\\ufe0f|\\u20e3)*$"}},"required":["emoji"]}}}},"responses":{"200":{"description":"Reaction set (replaces your previous one)"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}},"delete":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"messageId","in":"path"}],"responses":{"200":{"description":"Reaction removed"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/conversations/{conversationId}/attachments/{attachmentId}":{"get":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"conversationId","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"attachmentId","in":"path"}],"responses":{"200":{"description":"Photo as a data URL (members only)"},"401":{"description":"Sign in required"},"403":{"description":"Members only"},"404":{"description":"Not found"}}}},"/api/v1/gifs/search":{"get":{"tags":["Messages"],"parameters":[{"schema":{"type":"string","maxLength":100,"default":""},"required":false,"name":"q","in":"query"}],"responses":{"200":{"description":"GIPHY results (trending when q is empty); enabled=false without a key","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string"},"previewUrl":{"type":"string"},"width":{"type":"number"},"height":{"type":"number"}},"required":["id","title","url","previewUrl","width","height"]}}},"required":["enabled","results"]}}}},"401":{"description":"Sign in required"},"502":{"description":"GIPHY unavailable"}}}},"/api/v1/users/me/trail-log":{"get":{"tags":["Passport"],"responses":{"200":{"description":"Self-reported trail history, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["attended","hared","co_hared"]},"kennelSlug":{"type":"string","nullable":true},"kennelName":{"type":"string"},"country":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"eventType":{"type":"string"},"trailDate":{"type":"string","nullable":true},"quantity":{"type":"integer"},"notes":{"type":"string","nullable":true},"createdAt":{"type":"string"}},"required":["id","kind","kennelSlug","kennelName","country","title","eventType","trailDate","quantity","notes","createdAt"]}}},"required":["entries"]}}}},"401":{"description":"Not signed in"}}},"post":{"tags":["Passport"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["attended","hared","co_hared"]},"kennelSlug":{"type":"string","minLength":1},"kennelName":{"type":"string","minLength":1,"maxLength":120},"country":{"type":"string","maxLength":60},"title":{"type":"string","maxLength":200},"eventType":{"type":"string","enum":["trail","campout","cleanup","special"],"default":"trail"},"trailDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"quantity":{"type":"integer","minimum":1,"maximum":2000,"default":1},"notes":{"type":"string","maxLength":1000}},"required":["kind"]}}}},"responses":{"201":{"description":"Logged; includes any badges this earned"},"400":{"description":"Invalid entry"},"401":{"description":"Not signed in"},"404":{"description":"Kennel not found"},"409":{"description":"Already on your passport"}}}},"/api/v1/users/me/trail-log/{entryId}":{"put":{"tags":["Passport"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"entryId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["attended","hared","co_hared"]},"kennelSlug":{"type":"string","minLength":1},"kennelName":{"type":"string","minLength":1,"maxLength":120},"country":{"type":"string","maxLength":60},"title":{"type":"string","maxLength":200},"eventType":{"type":"string","enum":["trail","campout","cleanup","special"],"default":"trail"},"trailDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"quantity":{"type":"integer","minimum":1,"maximum":2000,"default":1},"notes":{"type":"string","maxLength":1000}},"required":["kind"]}}}},"responses":{"200":{"description":"Updated; includes any badges this earned"},"400":{"description":"Invalid entry"},"401":{"description":"Not signed in"},"404":{"description":"Not found"},"409":{"description":"Already on your passport"}}},"delete":{"tags":["Passport"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"entryId","in":"path"}],"responses":{"200":{"description":"Removed"},"401":{"description":"Not signed in"},"404":{"description":"Not found"}}}}}}