{"openapi":"3.1.0","info":{"title":"Leisure Travel Vans API","version":"0.0.0","description":"OpenAPI documentation generated from typed route definitions.\n\n## Host Split\n\n- Identity/OIDC/OAuth authority: `https://auth.myltv.cloud` (unversioned endpoints like `/.well-known/*` and `/oauth2/*`).\n- Application API host: `https://api.leisurevans.com` in production (preview/staging uses deployment URL).\n- Versioned prefixes (`/v1`, `/v2`) apply to application API endpoints (users/lists/leads/spots/etc), not identity protocol endpoints.\n\n## Authentication Quickstart\n\n### Relying app setup (OAuth code + PKCE)\n1. Register your client redirect URI.\n2. Redirect users to `GET /oauth2/authorize` with `response_type=code`, `state`, and PKCE (`code_challenge_method=s256`).\n3. Exchange code at `POST /oauth2/token`.\n4. Use `GET /oauth2/userinfo` for identity claims.\n5. Use `GET|POST /oauth2/end-session` for global logout.\n\n### Embedded website login setup\n1. Submit credentials to `POST /oauth2/embedded/login` from your server-side login action. The response returns authenticated user data under `user` with canonical domain `user.id`, `user.role`, and `user.product`.\n2. Request bootstrap ticket with `POST /oauth2/bootstrap-ticket`.\n3. Perform top-level bounce to `GET /oauth2/bootstrap-session?ticket=...` to establish central IdP session for cross-domain SSO.\n\n### Silent SSO\nAttempt `GET /oauth2/authorize` with `prompt=none` first. If session exists, callback returns immediately. If not, retry without `prompt=none`."},"servers":[{"url":"/","description":"Unversioned API (legacy)"},{"url":"/v1","description":"Version 1 API (legacy)"},{"url":"/v2","description":"Version 2 API"}],"tags":[{"name":"api","description":"Api endpoints"},{"name":"auth","description":"First-party authentication endpoints for embedded login and IdP session bootstrap. These endpoints are unversioned and live on the IdP host (auth.myltv.cloud), not /v2. POST /oauth2/embedded/login returns session-authenticated user data under `user` (including canonical domain `user.id`, `user.role`, and `user.product`) and does not duplicate role/product at the top level. Use POST /oauth2/bootstrap-ticket and GET /oauth2/bootstrap-session for direct website login + cross-domain SSO bootstrap."},{"name":"clubs","description":"Club and membership endpoints. Use `/clubs/{id}/directory` for the consent-filtered member-facing directory. `/clubs/{id}/members` and `/clubs/{id}/members/search` are privileged full-member endpoints for admins/current club leaders, with the member-reader service key accepted only by `/members`."},{"name":"dealers","description":"Namespaced proxy endpoints backed by dealer.api.leisurevans.com dealer resources. Successful responses are passthrough payloads (no local `{ data, requestId }` envelope). Use the `X-Request-Id` response header for trace correlation. Proxy-specific failures may include 405, 500, or 502."},{"name":"forms","description":"Signed WordPress form intake (`POST /forms/{formKey}`). Each formKey has a dedicated Valibot schema at runtime; OpenAPI publishes the payload families (Lead, ClubContact, MyLtvRedeem, WebFeedback, WebInfoRequest, Generic). See the Forms Intake section and the operation schema/examples for the full key catalog."},{"name":"keys","description":"API key lifecycle endpoints."},{"name":"leads","description":"Lead intake and reporting endpoints."},{"name":"lists","description":"Saved list and list-to-spot endpoints."},{"name":"myltv","description":"Namespaced proxy endpoints backed by Triple E Order API MyLTV resources. Collection routes remain raw passthroughs by default and return the standard `{ data, meta, requestId }` envelope when `paginate=true`. Use the `X-Request-Id` response header for trace correlation. Proxy-specific failures may include 405, 500, or 502."},{"name":"oauth2","description":"OAuth 2.0 endpoints for relying applications. These endpoints are unversioned and live on auth.myltv.cloud. Setup: 1) Register client redirect URI, 2) send users to GET /oauth2/authorize with code+PKCE, 3) exchange code at POST /oauth2/token, 4) call POST /oauth2/revoke on logout, 5) use prompt=none for silent SSO checks."},{"name":"oidc","description":"OpenID Connect metadata and identity endpoints on auth.myltv.cloud (unversioned). Start with GET /.well-known/openid-configuration, validate signatures via GET /jwks, and fetch claims from GET /oauth2/userinfo."},{"name":"openapi.scalar.json","description":"Openapi.scalar.json endpoints"},{"name":"order","description":"Namespaced proxy endpoints backed by Triple E Order API order resources. Successful responses are passthrough payloads (no local `{ data, requestId }` envelope). Use the `X-Request-Id` response header for trace correlation. Proxy-specific failures may include 405, 500, or 502."},{"name":"owners","description":"Owner portal endpoints."},{"name":"search","description":"Semantic vector search, ingestion interface dispatch (YouTube API/internal help centre API), run progress telemetry, and external provider sync endpoints."},{"name":"spots","description":"Spot catalog endpoints."},{"name":"subscriptions","description":"Subscription management endpoints."},{"name":"system","description":"System and health endpoints."},{"name":"users","description":"User profile and account endpoints. Product data is persisted in flattened columns (productModel/productFloorplan/productYear/productVin) for query performance and surfaced as a `product` object in API responses. `POST /users/register` creates auth + domain users, sends a verification email (`sendOnSignUp`), and returns `emailVerificationRequired: true` with no session cookies; sign-in is blocked until `emailVerified` is true. Pass optional `callbackURL` (or set `VERIFICATION_CALLBACK_URL`) so the link in the email redirects the browser back to your app after verification (must satisfy auth IdP `trustedOrigins`). On successful verification, domain `users.verified` is updated via `afterEmailVerification`. A newly committed club membership created by registration auto-join or `PUT /users/{userId}/clubs?action=join` sends a new-member notification to relational club leaders; repeated joins do not resend, and notification delivery failures do not fail registration or the membership update."},{"name":"webhooks","description":"Server-to-server signed webhooks (HMAC). Warranty registration updates ownership when a coach is delivered and registered."}],"x-tagGroups":[{"name":"Identity (auth.myltv.cloud, unversioned)","tags":["oauth2","oidc","auth","admin"]},{"name":"Application API (api host, /v1 and /v2)","tags":["users","webhooks","account-links","leads","forms","spots","lists","subscriptions","clubs","dealers","owners","keys","search"]},{"name":"Order API Proxy","tags":["coach","myltv","order"]},{"name":"Platform","tags":["system"]}],"paths":{"/users":{"get":{"operationId":"get-users","summary":"List users","description":"Returns users in canonical v2 envelope format.","tags":["users"],"responses":{"200":{"description":"User collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"search","in":"query","required":false,"schema":{"type":"string"},"description":"Prefix search value used with `fields`."},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated searchable fields (for example: email,firstName,lastName)."},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["asc","desc"]}},{"name":"club_slug","in":"query","required":false,"schema":{"type":"string","minLength":1},"description":"Optional club slug filter for global user search/listing."}]}},"/users/{userId}":{"get":{"operationId":"get-users-by-userId","summary":"Get user by ID","tags":["users"],"responses":{"200":{"description":"User resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}]},"put":{"operationId":"put-users-by-userId","summary":"Update user by ID","tags":["users"],"responses":{"200":{"description":"Updated user response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"object","properties":{"first":{"type":"string","nullable":true},"last":{"type":"string","nullable":true}}},"profile":{"type":"object","properties":{"phone":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true},"avatar":{"type":"string","nullable":true},"cover":{"type":"string","nullable":true},"facebook":{"type":"string","nullable":true},"instagram":{"type":"string","nullable":true},"coachNickname":{"type":"string","nullable":true,"maxLength":80},"twitter":{"type":"string","nullable":true},"website":{"type":"string","nullable":true}}},"product":{"type":"object","properties":{"model":{"type":"string","nullable":true},"floorplan":{"type":"string","nullable":true},"year":{"type":"string","nullable":true},"vin":{"type":"string","nullable":true}}},"address":{"type":"object","properties":{"street":{"type":"string","nullable":true},"street2":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"state":{"type":"string","nullable":true},"postcode":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"lat":{"type":"string","nullable":true},"lng":{"type":"string","nullable":true}}},"currentLocation":{"type":"object","nullable":true,"properties":{"lat":{"type":"string","nullable":true},"lng":{"type":"string","nullable":true}},"additionalProperties":false},"settings":{"type":"object","properties":{"shareContactDetails":{"type":"string"},"joinMailingList":{"type":"boolean"},"notifications":{"type":"object","properties":{"blogUpdates":{"type":"boolean"},"eventUpdates":{"type":"boolean"},"headUpdates":{"type":"boolean"}}}}}},"additionalProperties":false},"example":{"profile":{"coachNickname":"Rolling Zephyr"}}}}}},"delete":{"operationId":"delete-users-by-userId","summary":"Delete user by ID","tags":["users"],"responses":{"200":{"description":"Deletion acknowledgement.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","deleted":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","deleted":true},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}]}},"/users/{userId}/clubs":{"get":{"operationId":"get-users-by-userId-clubs","summary":"Get user clubs","tags":["users"],"responses":{"200":{"description":"User clubs response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time"},"isLeader":{"type":"boolean"}},"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"southwest-ltv-roadrunners-rv-club","joinDate":"2026-02-01T12:00:00.000Z","isLeader":false}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"southwest-ltv-roadrunners-rv-club","joinDate":"2026-02-01T12:00:00.000Z","isLeader":false}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]},"put":{"operationId":"put-users-by-userId-clubs","summary":"Update user clubs","description":"Join or leave an existing club as the account owner or an admin. Club identity is resolved from id; the optional slug is ignored compatibility metadata. This endpoint never creates, renames or reassigns shared clubs. Unknown clubs return 404. Cookie-authenticated writes must send `Content-Type: application/json` and an `Origin` exactly matching the configured `AUTH_ISSUER_URL` origin (`https://auth.myltv.cloud` in production). Missing headers or a cross-site origin return `403 Forbidden`. OAuth bearer callers use `Authorization: Bearer ...` and are not subject to this cookie-session check.","tags":["users"],"responses":{"200":{"description":"User clubs update response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time"},"isLeader":{"type":"boolean"}},"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"southwest-ltv-roadrunners-rv-club","joinDate":"2026-02-01T12:00:00.000Z","isLeader":false}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"southwest-ltv-roadrunners-rv-club","joinDate":"2026-02-01T12:00:00.000Z","isLeader":false}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"action","in":"query","required":true,"schema":{"type":"string","enum":["join","leave"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Existing club UUID, slug or numeric legacy WordPress ID."},"slug":{"type":"string","deprecated":true,"description":"Accepted for compatibility; cannot change club identity or metadata."}},"required":["id"],"additionalProperties":false}}}},"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/users/{userId}/lists":{"get":{"operationId":"get-users-by-userId-lists","summary":"Get user lists","tags":["users"],"responses":{"200":{"description":"User lists response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/users/{userId}/spots":{"get":{"operationId":"get-users-by-userId-spots","summary":"Get user spots","tags":["users"],"responses":{"200":{"description":"User spots response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/users/me/lists":{"get":{"operationId":"get-users-me-lists","summary":"Get current user lists","tags":["lists"],"responses":{"200":{"description":"Current user lists response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}]},"post":{"operationId":"post-users-me-lists","summary":"Create current user list","tags":["lists"],"responses":{"201":{"description":"Current user list created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["name"],"additionalProperties":false}}}}}},"/users/me/lists/{listId}":{"patch":{"operationId":"patch-users-me-lists-by-listId","summary":"Update current user list","tags":["lists"],"responses":{"200":{"description":"Current user list updated.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"operationId":"delete-users-me-lists-by-listId","summary":"Delete current user list","tags":["lists"],"responses":{"200":{"description":"Current user list deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}}]}},"/users/me/lists/{listId}/spots":{"post":{"operationId":"post-users-me-lists-by-listId-spots","summary":"Add spot to current user list","tags":["lists"],"responses":{"200":{"description":"Spot added to list.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spotId":{"type":"string","description":"Spot UUID or legacy 24-char ID."},"wpId":{"type":["integer","string"],"description":"WordPress spot ID."}},"anyOf":[{"required":["spotId"]},{"required":["wpId"]}],"additionalProperties":false}}}}}},"/users/me/lists/{listId}/spots/{spotId}":{"delete":{"operationId":"delete-users-me-lists-by-listId-spots-by-spotId","summary":"Remove spot from current user list","tags":["lists"],"responses":{"200":{"description":"Spot removed from list.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}},{"name":"spotId","in":"path","required":true,"schema":{"type":"string"},"description":"Spot UUID, legacy 24-char ID, or WordPress spot ID."}]}},"/users/me/spots/{spotId}/state":{"get":{"operationId":"get-users-me-spots-by-spotId-state","summary":"Get current user spot save state","tags":["spots"],"responses":{"200":{"description":"Spot save state response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"saved":{"type":"boolean"},"listIds":{"type":"array","items":{"type":"string"}}},"required":["saved","listIds"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"spotId","in":"path","required":true,"schema":{"type":"string"},"description":"Spot UUID, legacy 24-char ID, or WordPress spot ID."}]}},"/users/{userId}/rewards":{"get":{"operationId":"get-users-by-userId-rewards","summary":"Get user rewards","tags":["users"],"responses":{"200":{"description":"User rewards response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"amount":{"type":"integer","minimum":0},"date":{"type":"string","format":"date-time"},"description":{"type":"string"},"userId":{"type":"string","format":"uuid"}},"required":["id","amount","date","description","userId"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e112","amount":200,"date":"2026-02-12T18:00:00.000Z","description":"Referral for Art Vandelay.","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"},"balance":{"type":"integer"}},"required":["data","meta","requestId","balance"],"additionalProperties":false,"example":{"data":[{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e112","amount":200,"date":"2026-02-12T18:00:00.000Z","description":"Referral for Art Vandelay.","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8","balance":200}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]},"put":{"operationId":"put-users-by-userId-rewards","summary":"Update user rewards","tags":["users"],"responses":{"200":{"description":"User rewards update response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"Successfully added transaction for user."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Successfully added transaction for user."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}]}},"/users/{userId}/role":{"put":{"operationId":"put-users-by-userId-role","summary":"Update user role","tags":["users"],"responses":{"200":{"description":"User role update response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]}},"required":["id","email","role"],"additionalProperties":false}},"required":["message","user"],"additionalProperties":false,"example":{"message":"Successfully updated role for user josiah@example.com","user":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"josiah@example.com","role":"admin"}}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Successfully updated role for user josiah@example.com","user":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"josiah@example.com","role":"admin"}},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}]}},"/users/{userId}/password":{"post":{"operationId":"post-users-by-userId-password","summary":"Set user password","tags":["users"],"responses":{"200":{"description":"User password update response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"Password has been updated successfully."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Password has been updated successfully."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","minLength":8}},"required":["password"],"additionalProperties":false,"example":{"password":"new-password-123"}}}}}}},"/users/{userId}/change-email":{"post":{"operationId":"post-users-by-userId-change-email","summary":"Change user email","description":"Optional `return_to` / `redirect_uri` query params set IdP `callbackURL` when the target origin is allowlisted (see `getAllowedReturnToOrigins` in `server/return-to.ts`: `APP_BASE_URL`, auth URLs, password-reset base, absolute `AUTH_LOGIN_PAGE`, optional `AUTH_RETURN_TO_ALLOWED_ORIGINS`). Otherwise the default settings URL is used. Verification emails use `/auth/verify/{token}` with that target as `return_to`.","tags":["users"],"responses":{"200":{"description":"Change email response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"A verification email has been sent to your new email address. Please check your inbox."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"A verification email has been sent to your new email address. Please check your inbox."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"description":"Post-verification redirect (allowlisted origin or same-host path)."},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"deprecated":true,"description":"Alias for `return_to`."}]}},"/users/{userId}/change-password":{"post":{"operationId":"post-users-by-userId-change-password","summary":"Change user password","tags":["users"],"responses":{"200":{"description":"Change password response; auth IdP session cookie may be set.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"Password has been changed successfully."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Password has been changed successfully."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"headers":{"Set-Cookie":{"description":"Auth IdP session cookies (e.g., myltv.*). Set by auth IdP after successful password change.","schema":{"type":"string"}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currentPassword":{"type":"string","minLength":1},"newPassword":{"type":"string","minLength":8},"confirmPassword":{"type":"string","minLength":1}},"required":["currentPassword","newPassword","confirmPassword"],"additionalProperties":false,"example":{"currentPassword":"current-password","newPassword":"new-password-123","confirmPassword":"new-password-123"}}}}}}},"/users/confirm-email":{"get":{"operationId":"get-users-confirm-email","summary":"Confirm user email","description":"Completes email verification from a callback link token.","tags":["users"],"responses":{"200":{"description":"Confirm email response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"Your email has been verified successfully."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Your email has been verified successfully."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":1}}]},"post":{"operationId":"post-users-confirm-email","summary":"Confirm user email","description":"Completes email verification from a token submitted by a client app.","tags":["users"],"responses":{"200":{"description":"Confirm email response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"],"additionalProperties":false,"example":{"message":"Your email has been verified successfully."}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"message":"Your email has been verified successfully."},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1}},"required":["token"],"additionalProperties":false}}}}}},"/users/me":{"get":{"operationId":"get-users-me","summary":"Get current user","tags":["users"],"responses":{"200":{"description":"Current user response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/users/me/account-links":{"get":{"operationId":"get-users-me-account-links","summary":"List account links for current user","description":"Account linking is mutual-consent only: (1) User A sends an invite using the partner email, (2) User B accepts or declines the pending invite, (3) accepted links appear in both users' linked accounts, and (4) either user can unlink later. Returns incoming pending invites, outgoing pending invites, and accepted links for the current user.","tags":["account-links"],"responses":{"200":{"description":"Current user account links response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incoming":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"outgoing":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"accepted":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"message":{"type":"string"}},"required":["incoming","outgoing","accepted"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]},"post":{"operationId":"post-users-me-account-links","summary":"Create account link invite","description":"Step 1 of the account-link workflow. Creates a pending mutual-consent invitation by target email. The target user must respond before the link is active.","tags":["account-links"],"responses":{"200":{"description":"Updated account links after sending invite.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incoming":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"outgoing":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"accepted":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"message":{"type":"string"}},"required":["incoming","outgoing","accepted"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"],"additionalProperties":false}}}}}},"/users/me/account-links/{linkId}/respond":{"post":{"operationId":"post-users-me-account-links-by-linkId-respond","summary":"Respond to account link invite","description":"Step 2 of the account-link workflow. Accepts or declines a pending invite for the authenticated target user.","tags":["account-links"],"responses":{"200":{"description":"Updated account links after response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incoming":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"outgoing":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"accepted":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"message":{"type":"string"}},"required":["incoming","outgoing","accepted"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["accept","decline"]}},"required":["action"],"additionalProperties":false}}}}}},"/users/me/account-links/{linkId}":{"delete":{"operationId":"delete-users-me-account-links-by-linkId","summary":"Unlink or revoke account link","description":"Step 3 of the account-link workflow for lifecycle management. Revokes a pending outgoing invite or unlinks an accepted account link.","tags":["account-links"],"responses":{"200":{"description":"Updated account links after removal.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incoming":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"outgoing":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"accepted":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","accepted","declined","revoked"]},"direction":{"type":"string","enum":["incoming","outgoing"]},"createdAt":{"type":"string","format":"date-time"},"respondedAt":{"type":"string","format":"date-time","nullable":true},"updatedAt":{"type":"string","format":"date-time"},"otherUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"}},"required":["id","email","firstName","lastName"],"additionalProperties":false}},"required":["id","status","direction","createdAt","respondedAt","updatedAt","otherUser"],"additionalProperties":false}},"message":{"type":"string"}},"required":["incoming","outgoing","accepted"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Conflict response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}}]}},"/users/search":{"get":{"operationId":"get-users-search","summary":"Search users","tags":["users"],"responses":{"200":{"description":"User search response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"email","in":"query","required":false,"schema":{"type":"string","format":"email"}},{"name":"id","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/users/unverified":{"get":{"operationId":"get-users-unverified","summary":"List unverified users","description":"Returns unverified users with pagination and optional filters.","tags":["users"],"responses":{"200":{"description":"Unverified users response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":false,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"search","in":"query","required":false,"schema":{"type":"string"}},{"name":"role","in":"query","required":false,"schema":{"type":"string","enum":["user","admin","club_leader"]}}]}},"/users/register":{"post":{"operationId":"post-users-register","summary":"Register domain user (on-order GUID or VIN)","description":"Creates a new user. Validates coach against the order API. Triggers auth IdP sign-up with `sendOnSignUp` and `requireEmailVerification`: a verification email is sent automatically; the client must complete verification before email/password sign-in succeeds (typically `403` until verified). No `Set-Cookie` on this response. Domain `users.verified` is set when verification completes (`afterEmailVerification`). Use `method: \"guid\"` for builds in progress (`ownershipStatus`: on_order); use `method: \"vin\"` for delivered units (`ownershipStatus`: current_owner).","tags":["users"],"responses":{"201":{"description":"User registered; verification email sent. Response body is `{ data: { user, emailVerificationRequired: true }, requestId }` with no session cookies until the user verifies and signs in via auth IdP.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"user":{"type":"object","description":"Created domain user. Product fields may be partial until delivery; `ownershipStatus` is `on_order` for GUID signup and `current_owner` for VIN signup.","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"},"coachGuid":{"type":"string","nullable":true},"ownershipStatus":{"type":"string","enum":["on_order","current_owner"],"nullable":true},"product":{"type":"object","additionalProperties":true,"nullable":true},"profile":{"type":"object","nullable":true,"properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80}},"additionalProperties":true}},"required":["id","email","firstName","lastName"],"additionalProperties":true},"emailVerificationRequired":{"type":"boolean","const":true,"description":"Always true for this endpoint: registration does not issue a session. After the user verifies via the emailed link, domain `users.verified` is updated server-side."}},"required":["user","emailVerificationRequired"],"additionalProperties":false,"example":{"user":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"owner@example.com","firstName":"Avery","lastName":"Morgan","coachGuid":"coach-guid-example","ownershipStatus":"on_order","product":{"model":"Unity","floorplan":"FX","year":"2026","vin":null},"profile":{"coachNickname":"Rolling Zephyr"}},"emailVerificationRequired":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"user":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"owner@example.com","firstName":"Avery","lastName":"Morgan","coachGuid":"coach-guid-example","ownershipStatus":"on_order","product":{"model":"Unity","floorplan":"FX","year":"2026","vin":null},"profile":{"coachNickname":"Rolling Zephyr"}},"emailVerificationRequired":true},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"description":"Email already registered (domain or auth).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"422":{"description":"Coach not found for supplied GUID or VIN.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"429":{"description":"Registration rate limit exceeded.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"error":{"type":"string"}},"required":["success","message"]}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Order API unreachable or error while validating coach.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","title":"vin","description":"Register new user with VIN","required":["method","vin","firstName","lastName","email","password"],"properties":{"method":{"type":"string","enum":["vin"]},"vin":{"type":"string","minLength":1},"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"profile":{"type":"object","description":"Optional profile fields saved to `user.profile`.","properties":{"phone":{"type":"string"},"bio":{"type":"string"},"avatar":{"type":"string"},"cover":{"type":"string"},"facebook":{"type":"string"},"instagram":{"type":"string"},"coachNickname":{"type":"string","maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"twitter":{"type":"string"},"website":{"type":"string"}},"additionalProperties":false},"address":{"type":"object","nullable":true,"description":"Optional address object saved to `user.address`.","properties":{"street":{"type":"string"},"street2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postcode":{"type":"string"},"country":{"type":"string"},"lat":{"type":"string"},"lng":{"type":"string"}},"additionalProperties":false},"clubs":{"type":"array","description":"Optional existing clubs to join after registration. Joins are best-effort: missing clubs or failed membership writes are skipped without blocking account creation or later joins. Registration never creates or changes shared clubs.","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","minLength":1,"description":"Club identifier accepted by the club membership endpoint: UUID, slug, or legacy WP id."},"slug":{"type":"string","minLength":1,"deprecated":true,"description":"Accepted for compatibility and ignored for identity and catalog changes; only id resolves the club."}},"additionalProperties":false}},"settings":{"type":"object","description":"Optional registration consent. Omitted settings or fields default to no mailing/notification opt-ins and no directory sharing. Transactional verification email is still required.","properties":{"joinMailingList":{"type":"boolean","default":false},"shareContactDetails":{"type":"string","enum":["none","withTC","withAll"],"default":"none"},"notifications":{"type":"object","properties":{"blogUpdates":{"type":"boolean","default":false},"eventUpdates":{"type":"boolean","default":false},"headUpdates":{"type":"boolean","default":false}},"additionalProperties":false}},"additionalProperties":false},"callbackURL":{"type":"string","minLength":1,"description":"Optional redirect after the user completes email verification (absolute URL or app path). Embedded in the verification link by auth IdP; must be allowed by IdP `trustedOrigins`. Falls back to `VERIFICATION_CALLBACK_URL`, then `/`."}},"additionalProperties":false},{"type":"object","title":"guid","description":"Register new user with coach GUID (on-order)","required":["method","coachGuid","firstName","lastName","email","password"],"properties":{"method":{"type":"string","enum":["guid"]},"coachGuid":{"type":"string","minLength":1,"description":"Coach GUID from the order system (e.g. marketing link query param)."},"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"profile":{"type":"object","description":"Optional profile fields saved to `user.profile`.","properties":{"phone":{"type":"string"},"bio":{"type":"string"},"avatar":{"type":"string"},"cover":{"type":"string"},"facebook":{"type":"string"},"instagram":{"type":"string"},"coachNickname":{"type":"string","maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"twitter":{"type":"string"},"website":{"type":"string"}},"additionalProperties":false},"address":{"type":"object","nullable":true,"description":"Optional address object saved to `user.address`.","properties":{"street":{"type":"string"},"street2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postcode":{"type":"string"},"country":{"type":"string"},"lat":{"type":"string"},"lng":{"type":"string"}},"additionalProperties":false},"clubs":{"type":"array","description":"Optional existing clubs to join after registration. Joins are best-effort: missing clubs or failed membership writes are skipped without blocking account creation or later joins. Registration never creates or changes shared clubs.","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","minLength":1,"description":"Club identifier accepted by the club membership endpoint: UUID, slug, or legacy WP id."},"slug":{"type":"string","minLength":1,"deprecated":true,"description":"Accepted for compatibility and ignored for identity and catalog changes; only id resolves the club."}},"additionalProperties":false}},"settings":{"type":"object","description":"Optional registration consent. Omitted settings or fields default to no mailing/notification opt-ins and no directory sharing. Transactional verification email is still required.","properties":{"joinMailingList":{"type":"boolean","default":false},"shareContactDetails":{"type":"string","enum":["none","withTC","withAll"],"default":"none"},"notifications":{"type":"object","properties":{"blogUpdates":{"type":"boolean","default":false},"eventUpdates":{"type":"boolean","default":false},"headUpdates":{"type":"boolean","default":false}},"additionalProperties":false}},"additionalProperties":false},"callbackURL":{"type":"string","minLength":1,"description":"Optional redirect after the user completes email verification (absolute URL or app path). Embedded in the verification link by auth IdP; must be allowed by IdP `trustedOrigins`. Falls back to `VERIFICATION_CALLBACK_URL`, then `/`."}},"additionalProperties":false}]}}}},"security":[]}},"/webhooks/warranty-registration":{"post":{"operationId":"post-webhooks-warranty-registration","summary":"Warranty registration webhook","description":"HMAC-signed callback when a coach is warranty-registered (delivery). Matches users by `coachGuid` or `productVin`, sets `ownershipStatus` to current_owner, and fills VIN when missing. Same signature scheme as form intake: `sha256=<hex>` over `${x-ltv-timestamp}.${rawBody}`.","tags":["webhooks"],"responses":{"200":{"description":"Users updated (or none matched; still 200 so the warranty system is not blocked).","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"updated":{"type":"integer","minimum":0},"matchedUserIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":["updated","matchedUserIds"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"x-ltv-timestamp","in":"header","required":true,"schema":{"type":"string"},"description":"Unix timestamp (seconds or milliseconds) or ISO datetime used for signature verification."},{"name":"x-ltv-signature","in":"header","required":true,"schema":{"type":"string"},"description":"HMAC signature in format 'sha256=<hex>' over `${x-ltv-timestamp}.${rawBody}`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["vin","coachGuid","registeredAt"],"properties":{"vin":{"type":"string","minLength":1},"coachGuid":{"type":"string","minLength":1},"registeredAt":{"type":"string","description":"ISO-8601 or opaque timestamp from warranty system."}},"additionalProperties":false}}}},"security":[]}},"/keys/create":{"post":{"operationId":"post-keys-create","summary":"Create API key","description":"Creates a managed API key for an internal integration. The new plaintext token is returned once and only its SHA-256 hash is stored. Later list/detail reads return key=null and a display prefix. Existing plaintext legacy keys are preserved. New keys have no operation permissions unless explicit operationGrants are supplied; principalKind=service is required for WordPress club operations and vector:ingest. Revoked or expired keys cannot authenticate. Administrators use the auth-host alias /oauth2/admin/keys/create.\n\n### Try It (Internal/Admin)\n1. Use a controlled test email/label in non-production first.\n2. POST a JSON body with `email`, `label`, `principalKind`, and explicit `operationGrants`; optionally narrow with `scopes` and set `expiresAt`.\n3. Save the returned key in the integration immediately; new tokens cannot be retrieved later.","tags":["keys"],"responses":{"201":{"description":"API key created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"label":{"type":"string"},"key":{"type":"string","nullable":true,"description":"New plaintext tokens are returned once on creation; later reads return null. Existing legacy plaintext tokens remain visible."},"tokenPrefix":{"type":"string","nullable":true,"description":"Display identifier only; never an authentication credential."},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","label","key","tokenPrefix","principalKind","scopes","operationGrants","expiresAt","revokedAt","lastUsedAt","createdAt"],"additionalProperties":false,"example":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"label":{"type":"string","minLength":1,"maxLength":255},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true}},"required":["email","label"],"additionalProperties":false}}}},"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/lists":{"get":{"operationId":"get-lists","summary":"List saved lists","tags":["lists"],"responses":{"200":{"description":"List collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}]}},"/lists/slug/{slug}":{"get":{"operationId":"get-lists-slug-by-slug","summary":"Get list by public slug","tags":["lists"],"responses":{"200":{"description":"List resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"spots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}]}},"/lists/{listId}":{"get":{"operationId":"get-lists-by-listId","summary":"Get list by ID","tags":["lists"],"responses":{"200":{"description":"List resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"spots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}}]}},"/lists/{listId}/spots":{"get":{"operationId":"get-lists-by-listId-spots","summary":"Get spots for list","tags":["lists"],"responses":{"200":{"description":"List spots response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"listId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}}]}},"/spots":{"get":{"operationId":"get-spots","summary":"List spots","tags":["spots"],"responses":{"200":{"description":"Spot collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]},"post":{"operationId":"post-spots","summary":"Create or reuse a spot and add it to an owned list","description":"Existing WordPress spot IDs are reused without changing their shared name, slug, note or timestamps. Name and note apply only when creating a new canonical spot. The response contains the destination list and its spots.","tags":["spots"],"responses":{"200":{"description":"Existing canonical spot added to the owned list without modification.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"spots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"201":{"description":"Canonical spot created and added to the owned list.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"visibility":{"type":"string","enum":["public","private"]},"spots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}}}},"required":["id","userId","name","visibility"],"additionalProperties":false,"example":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"5ac64c53-8d6e-4f16-9309-5f718eb9225a","legacyId":"65a7e9b3a0f3f4c2d7b7e221","userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","name":"Weekend Trips","description":"Spots to revisit this summer.","slug":"weekend-trips","visibility":"public"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"wpId":{"type":"integer"},"listId":{"type":"string","minLength":1,"description":"An owned list UUID or legacy Mongo ID."},"note":{"type":"string","nullable":true,"description":"Initial shared note for a new spot only."}},"required":["name","wpId","listId"],"additionalProperties":false}}}}}},"/spots/{spotId}":{"get":{"operationId":"get-spots-by-spotId","summary":"Get spot by ID","tags":["spots"],"responses":{"200":{"description":"Spot resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"spotId","in":"path","required":true,"schema":{"type":"string"}}]},"put":{"operationId":"put-spots-by-spotId","summary":"Update spot by ID","tags":["spots"],"responses":{"200":{"description":"Updated spot response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"wpId":{"type":"number"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","legacyId":"65a7e9b3a0f3f4c2d7b7e331","wpId":4832,"name":"Banff National Park","slug":"banff-national-park"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"spotId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"wpId":{"type":"number"},"slug":{"type":"string"}},"additionalProperties":false}}}}},"delete":{"operationId":"delete-spots-by-spotId","summary":"Delete spot by ID","tags":["spots"],"responses":{"200":{"description":"Deletion acknowledgement.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false,"example":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","deleted":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"4f667949-7e7b-4068-a7ea-16cdad57ed08","deleted":true},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"spotId","in":"path","required":true,"schema":{"type":"string"}}]}},"/leads":{"get":{"operationId":"get-leads","summary":"List leads","tags":["leads"],"responses":{"200":{"description":"Lead collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"leadId":{"type":"string","format":"uuid"},"type":{"type":"string"},"customerEmail":{"type":"string","format":"email","nullable":true},"customerFirstName":{"type":"string","nullable":true},"customerLastName":{"type":"string"},"date":{"type":"string","format":"date-time"}},"required":["id","leadId","type"],"additionalProperties":false,"example":{"id":"9f4f1a5d-7893-4f5d-acf3-9ec00ad22ef2","legacyId":"65a7e9b3a0f3f4c2d7b7e441","leadId":"db1f70d3-cf8e-4cb0-a6eb-8965c27a5db8","type":"newsletter","customerEmail":"owner@example.com","customerFirstName":"Avery","customerLastName":"Morgan","date":"2026-02-12T17:11:24.502Z"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9f4f1a5d-7893-4f5d-acf3-9ec00ad22ef2","legacyId":"65a7e9b3a0f3f4c2d7b7e441","leadId":"db1f70d3-cf8e-4cb0-a6eb-8965c27a5db8","type":"newsletter","customerEmail":"owner@example.com","customerFirstName":"Avery","customerLastName":"Morgan","date":"2026-02-12T17:11:24.502Z"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/leads/{leadId}":{"get":{"operationId":"get-leads-by-leadId","summary":"Get lead by ID","tags":["leads"],"responses":{"200":{"description":"Lead resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"leadId":{"type":"string","format":"uuid"},"type":{"type":"string"},"customerEmail":{"type":"string","format":"email","nullable":true},"customerFirstName":{"type":"string","nullable":true},"customerLastName":{"type":"string"},"date":{"type":"string","format":"date-time"}},"required":["id","leadId","type"],"additionalProperties":false,"example":{"id":"9f4f1a5d-7893-4f5d-acf3-9ec00ad22ef2","legacyId":"65a7e9b3a0f3f4c2d7b7e441","leadId":"db1f70d3-cf8e-4cb0-a6eb-8965c27a5db8","type":"newsletter","customerEmail":"owner@example.com","customerFirstName":"Avery","customerLastName":"Morgan","date":"2026-02-12T17:11:24.502Z"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"9f4f1a5d-7893-4f5d-acf3-9ec00ad22ef2","legacyId":"65a7e9b3a0f3f4c2d7b7e441","leadId":"db1f70d3-cf8e-4cb0-a6eb-8965c27a5db8","type":"newsletter","customerEmail":"owner@example.com","customerFirstName":"Avery","customerLastName":"Morgan","date":"2026-02-12T17:11:24.502Z"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"leadId","in":"path","required":true,"schema":{"type":"string"}}]}},"/leads/count":{"get":{"operationId":"get-leads-count","summary":"Get lead counts","tags":["leads"],"responses":{"200":{"description":"Lead aggregate response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer","minimum":0}},"required":["date","count"],"additionalProperties":false},"example":[{"date":"2026-02-01","count":14}]},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":[{"date":"2026-02-01","count":14}],"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/leads/count/dealer":{"get":{"operationId":"get-leads-count-dealer","summary":"Get lead counts by dealer","tags":["leads"],"responses":{"200":{"description":"Lead-by-dealer aggregate response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"dealer":{"type":"string"},"count":{"type":"integer","minimum":0}},"required":["count"],"additionalProperties":false},"example":[{"dealer":"Regina RV","count":22}]},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":[{"dealer":"Regina RV","count":22}],"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/leads/new/{leadType}":{"post":{"operationId":"post-leads-new-by-leadType","summary":"Create lead (deprecated)","tags":["leads"],"responses":{"410":{"description":"Deprecated lead write endpoint response.","content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"expectedSchema":{"type":"object","properties":{"migration":{"type":"string"},"example":{"type":"string"}},"additionalProperties":true}},"required":["title","status"],"additionalProperties":true}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"leadType","in":"path","required":true,"schema":{"type":"string"}}]}},"/forms/{formKey}":{"post":{"operationId":"post-forms-by-formKey","summary":"Intake WordPress form submission","description":"Accepts signed WordPress webhook payloads for async processing.\nRequires signature headers and idempotent delivery metadata.\n\nSupported `formKey` values and payload families:\n\n| formKey | Schema | Notes |\n|---|---|---|\n| `lead:brochure-download` | LeadFormPayload | Creates CRM lead |\n| `lead:factory-tour` | LeadFormPayload | Creates CRM lead |\n| `lead:quote-request` | LeadFormPayload | Creates CRM lead |\n| `lead:email-summary` | LeadFormPayload | Creates CRM lead |\n| `lead:build` | LeadFormPayload | Creates CRM lead (`isBuild`) |\n| `club:contact` | ClubContactFormPayload | Notifies club leaders |\n| `myltv:redeem` | MyLtvRedeemFormPayload | Redeems myLTV points |\n| `myltv:brochure-request` | GenericFormPayload | Connects to external service for processing |\n| `myltv:claim` | GenericFormPayload | Connects to external service for processing |\n| `myltv:registration-help` | GenericFormPayload | Connects to external service for processing |\n| `explorers:application` | GenericFormPayload | Connects to external service for processing |\n| `dealer:show-feedback` | GenericFormPayload | Connects to external service for processing |\n| `web:feedback` | WebFeedbackFormPayload | `rating`, `comment`, `pageUrl`, `pageTitle`; optional `user` |\n| `web:info-request` | WebInfoRequestFormPayload | `comment`; optional `user` and `product` |\n\nRequest body schemas for each family are published on this operation (see Schema / Examples).\n\nUnknown `formKey` values return `400`. Payload shape is validated against the schema for that key.","tags":["forms"],"responses":{"200":{"description":"Duplicate delivery accepted with original submission id.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"submissionId":{"type":"string","format":"uuid"},"formKey":{"type":"string","enum":["explorers:application","lead:brochure-download","lead:factory-tour","lead:quote-request","lead:email-summary","lead:build","club:contact","myltv:redeem","myltv:brochure-request","myltv:claim","myltv:registration-help","dealer:show-feedback","web:feedback","web:info-request"]},"status":{"type":"string"},"duplicate":{"type":"boolean"}},"required":["submissionId","formKey","status"],"additionalProperties":true}},"required":["data"],"additionalProperties":true}}}},"202":{"description":"Form submission accepted for async processing.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"submissionId":{"type":"string","format":"uuid"},"formKey":{"type":"string","enum":["explorers:application","lead:brochure-download","lead:factory-tour","lead:quote-request","lead:email-summary","lead:build","club:contact","myltv:redeem","myltv:brochure-request","myltv:claim","myltv:registration-help","dealer:show-feedback","web:feedback","web:info-request"]},"status":{"type":"string"}},"required":["submissionId","formKey","status"],"additionalProperties":true}},"required":["data"],"additionalProperties":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"formKey","in":"path","required":true,"schema":{"type":"string","enum":["explorers:application","lead:brochure-download","lead:factory-tour","lead:quote-request","lead:email-summary","lead:build","club:contact","myltv:redeem","myltv:brochure-request","myltv:claim","myltv:registration-help","dealer:show-feedback","web:feedback","web:info-request"]},"description":"Canonical form key (case-insensitive; URL-encoded colons accepted)."},{"name":"x-ltv-timestamp","in":"header","required":true,"schema":{"type":"string"},"description":"Unix timestamp (seconds or milliseconds) or ISO datetime used for signature verification."},{"name":"x-ltv-delivery-id","in":"header","required":true,"schema":{"type":"string"},"description":"Unique delivery identifier for idempotency and replay protection."},{"name":"x-ltv-signature","in":"header","required":true,"schema":{"type":"string"},"description":"HMAC signature in format 'sha256=<hex>' over `${x-ltv-timestamp}.${rawBody}`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","title":"LeadFormPayload","description":"Payload for `lead:brochure-download`, `lead:factory-tour`, `lead:quote-request`, `lead:email-summary`, and `lead:build`. Creates a CRM lead and fans out.","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Required customer email."},"firstName":{"type":"string"},"lastName":{"type":"string"},"phone":{"type":"string"},"address":{"type":"string"},"addressMore":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"country":{"type":"string"},"dealer":{"description":"Dealer name string, or dealer object with id/location metadata.","oneOf":[{"type":"string"},{"type":"object","properties":{"dealerId":{"oneOf":[{"type":"number"},{"type":"string"}]},"dealerName":{"type":"string"},"locationId":{"oneOf":[{"type":"number"},{"type":"string"}]},"location":{"type":"string"}},"additionalProperties":true}]},"dealerId":{"oneOf":[{"type":"number"},{"type":"string"}]},"dealerLocation":{"oneOf":[{"type":"number"},{"type":"string"}]},"note":{"type":"string"},"message":{"type":"string","description":"Alias for `note` / `comment`."},"comment":{"type":"string","description":"Alias for `note` / `message`."},"model":{"type":"string"},"buildUrl":{"type":"string"},"isBuild":{"description":"Whether lead:quote-request or lead:email-summary includes a configured build; defaults to false. Other lead forms ignore this field: lead:build is always a build, and other lead forms are not.","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"summary":{"description":"Opaque build/summary payload."},"options":{"description":"Array of strings, or a comma-separated string.","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"floorplans":{"description":"Array of strings, or a comma-separated string.","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"models":{"description":"Array of strings, or a comma-separated string.","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"modelsRequested":{"description":"Array of strings, or a comma-separated string.","oneOf":[{"type":"array","items":{"type":"string"}},{"type":"string"}]},"dealerFollowup":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"dealerFollowUp":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"joinMailingList":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"newsletterOpt":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"newsletter":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"currentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"isCurrentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"owner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}},"additionalProperties":true},{"type":"object","title":"ClubContactFormPayload","description":"Payload for `club:contact`. Requires `firstName`, `lastName`, `message`, and one of `clubSlug` / `clubId` / `club`.","required":["firstName","lastName","message"],"properties":{"clubSlug":{"type":"string","description":"Preferred club identifier."},"clubId":{"type":"string"},"club":{"type":"string","description":"Fallback club identifier."},"firstName":{"type":"string","minLength":1},"lastName":{"type":"string","minLength":1},"message":{"type":"string","minLength":1},"email":{"type":"string","format":"email"},"joinMailingList":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"currentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}},"additionalProperties":true},{"type":"object","title":"MyLtvRedeemFormPayload","description":"Payload for `myltv:redeem`. Redeems myLTV points for the given user.","required":["amount","userId"],"properties":{"amount":{"description":"Positive integer point amount (number or numeric string).","oneOf":[{"type":"integer","minimum":1},{"type":"string"}]},"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"lastName":{"type":"string"},"joinMailingList":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"currentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}},"additionalProperties":true},{"type":"object","title":"WebFeedbackFormPayload","description":"Payload for `web:feedback`.","required":["rating","comment","pageUrl","pageTitle"],"properties":{"rating":{"type":"string","enum":["1","2","3","4","5"],"description":"Star rating as a string enum."},"comment":{"type":"string","minLength":1},"pageUrl":{"type":"string","minLength":1,"description":"URL of the page where feedback was submitted."},"pageTitle":{"type":"string","minLength":1,"description":"Document title of the page where feedback was submitted."},"user":{"type":"object","description":"Optional user context.","required":["name","email"],"properties":{"name":{"type":"string","minLength":1},"email":{"type":"string","format":"email"}},"additionalProperties":false}},"additionalProperties":false},{"type":"object","title":"WebInfoRequestFormPayload","description":"Payload for `web:info-request`.","required":["comment"],"properties":{"comment":{"type":"string","minLength":1},"user":{"type":"object","description":"Optional user context.","required":["name","email"],"properties":{"name":{"type":"string","minLength":1},"email":{"type":"string","format":"email"}},"additionalProperties":false},"product":{"type":"object","description":"Optional product context.","required":["year","model","floorplan"],"properties":{"year":{"type":"string","minLength":1},"model":{"type":"string","minLength":1},"floorplan":{"type":"string","minLength":1}},"additionalProperties":false}},"additionalProperties":false},{"type":"object","title":"GenericFormPayload","description":"Loose JSON object for generic form keys. Common optional contact fields listed below; additional properties are accepted.","properties":{"email":{"type":"string","format":"email"},"firstName":{"type":"string"},"name":{"type":"string","description":"Alias for `firstName`."},"lastName":{"type":"string"},"phone":{"type":"string"},"message":{"type":"string"},"comment":{"type":"string"},"joinMailingList":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"newsletterOpt":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"newsletter":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"currentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"isCurrentOwner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"owner":{"description":"Accepts boolean, or common string/number truthy values (`true`/`false`, `yes`/`no`, `1`/`0`, `on`/`off`).","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]}},"additionalProperties":true}]},"examples":{"lead:factory-tour":{"summary":"lead:factory-tour","description":"Lead form — factory tour request.","value":{"email":"lead@example.com","firstName":"Alex","lastName":"Buyer","phone":"+1-555-123-4567","model":"Unity","joinMailingList":true}},"lead:brochure-download":{"summary":"lead:brochure-download","description":"Lead form — brochure download with dealer + floorplans.","value":{"email":"lead@example.com","firstName":"Alex","lastName":"Buyer","dealer":{"dealerId":11297,"dealerName":"GNR Camping World","locationId":1},"models":["Unity"],"floorplans":["Unity - FX","Unity - Twin Bed"],"comment":"Please send digital brochures.","dealerFollowUp":true,"joinMailingList":false}},"club:contact":{"summary":"club:contact","description":"Club leader contact message.","value":{"clubSlug":"prairie-rambers","firstName":"Jamie","lastName":"Owner","email":"owner@example.com","message":"Interested in joining the next rally."}},"myltv:redeem":{"summary":"myltv:redeem","description":"Redeem myLTV points.","value":{"amount":50,"userId":"f8f659fe-1f16-4d15-b58b-9e6623ef4023","email":"owner@example.com","firstName":"Jamie","lastName":"Owner","joinMailingList":true,"currentOwner":true}},"myltv:brochure-request":{"summary":"myltv:brochure-request (generic)","description":"Generic form key — arbitrary contact fields accepted.","value":{"email":"owner@example.com","firstName":"Jamie","lastName":"Owner","message":"Please send me details."}},"web:feedback":{"summary":"web:feedback","description":"Website feedback with star rating and page context.","value":{"rating":"5","comment":"Love the new site.","pageUrl":"https://leisurevans.com/models/unity","pageTitle":"Unity | Leisure Travel Vans","user":{"name":"Jamie Owner","email":"owner@example.com"}}},"web:info-request":{"summary":"web:info-request","description":"General website info request with optional user/product context.","value":{"comment":"Looking for Unity brochure pricing.","user":{"name":"Jamie Owner","email":"owner@example.com"},"product":{"year":"2026","model":"Unity","floorplan":"FX"}}}}}}}}},"/subscriptions":{"get":{"operationId":"get-subscriptions","summary":"List subscriptions","description":"Requires a linked administrator. OAuth access grants must also have openid and profile scopes. API keys and dealer/WordPress service keys do not grant receiver-management access. Responses are not cacheable.","tags":["subscriptions"],"responses":{"200":{"description":"Subscription collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"event":{"type":"string"},"target":{"type":"string","nullable":true}},"required":["id","event"],"additionalProperties":false,"example":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]},"post":{"operationId":"post-subscriptions","summary":"Create subscription","description":"Requires a linked administrator session or valid administrator OAuth grant with openid and profile scopes. Cookie-authenticated changes require same-origin JSON requests. This stores a destination; it does not send or verify a callback.","tags":["subscriptions"],"responses":{"201":{"description":"Subscription created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"event":{"type":"string"},"target":{"type":"string","nullable":true}},"required":["id","event"],"additionalProperties":false,"example":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"target":{"type":"string"}},"required":["event"],"additionalProperties":false}}}}}},"/subscriptions/{id}":{"get":{"operationId":"get-subscriptions-by-id","summary":"Get subscription by ID","description":"Requires a linked administrator session or valid administrator OAuth grant with openid and profile scopes. UUIDs and preserved legacy IDs identify the same receiver. Responses are not cacheable.","tags":["subscriptions"],"responses":{"200":{"description":"Subscription resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"event":{"type":"string"},"target":{"type":"string","nullable":true}},"required":["id","event"],"additionalProperties":false,"example":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","legacyId":"65a7e9b3a0f3f4c2d7b7e551","event":"lead.created","target":"https://example.com/hooks/lead-created"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"operationId":"delete-subscriptions-by-id","summary":"Delete subscription by ID","description":"Requires a linked administrator session or valid administrator OAuth grant with openid and profile scopes. Cookie-authenticated changes require same-origin JSON requests, including a JSON Content-Type on DELETE.","tags":["subscriptions"],"responses":{"200":{"description":"Deletion acknowledgement.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false,"example":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","deleted":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","deleted":true},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/keys":{"get":{"operationId":"get-keys","summary":"List API keys","description":"Lists managed controls for administrators. Existing legacy plaintext key values remain available. New keys return key=null and tokenPrefix; raw hashes are never exposed. Auth-host alias: /oauth2/admin/keys.","tags":["keys"],"responses":{"200":{"description":"API key collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"label":{"type":"string"},"key":{"type":"string","nullable":true,"description":"New plaintext tokens are returned once on creation; later reads return null. Existing legacy plaintext tokens remain visible."},"tokenPrefix":{"type":"string","nullable":true,"description":"Display identifier only; never an authentication credential."},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","label","key","tokenPrefix","principalKind","scopes","operationGrants","expiresAt","revokedAt","lastUsedAt","createdAt"],"additionalProperties":false,"example":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/keys/{id}":{"get":{"operationId":"get-keys-by-id","summary":"Get API key by ID","tags":["keys"],"responses":{"200":{"description":"API key resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"label":{"type":"string"},"key":{"type":"string","nullable":true,"description":"New plaintext tokens are returned once on creation; later reads return null. Existing legacy plaintext tokens remain visible."},"tokenPrefix":{"type":"string","nullable":true,"description":"Display identifier only; never an authentication credential."},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","label","key","tokenPrefix","principalKind","scopes","operationGrants","expiresAt","revokedAt","lastUsedAt","createdAt"],"additionalProperties":false,"example":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]}]},"put":{"operationId":"put-keys-by-id","summary":"Update managed API key","description":"Updates the label, principal kind, exact operation grants, optional scope narrowing, expiry or revocation. At least one change is required. Omitted controls remain unchanged; null clears expiry or revocation. Tokens and owner emails cannot be changed. Revocation immediately rejects future authentication. Auth-host alias: /oauth2/admin/keys/{id}.","tags":["keys"],"responses":{"200":{"description":"Updated API key resource response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"label":{"type":"string"},"key":{"type":"string","nullable":true,"description":"New plaintext tokens are returned once on creation; later reads return null. Existing legacy plaintext tokens remain visible."},"tokenPrefix":{"type":"string","nullable":true,"description":"Display identifier only; never an authentication credential."},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","label","key","tokenPrefix","principalKind","scopes","operationGrants","expiresAt","revokedAt","lastUsedAt","createdAt"],"additionalProperties":false,"example":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"3f8b4b8e-5ecf-46c3-b85f-53a8d85f4333","email":"integrations@example.com","label":"WordPress clubs","key":null,"tokenPrefix":"redacted-prefix","principalKind":"service","scopes":[],"operationGrants":["clubs:read","clubs:members:read","users:read","clubs:leaders:write"],"expiresAt":null,"revokedAt":null,"lastUsedAt":null,"createdAt":"2026-09-21T12:00:00.000Z"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":255},"principalKind":{"type":"string","enum":["user","service"]},"scopes":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Empty adds no narrowing; nonempty must include the operation being requested."},"operationGrants":{"type":"array","items":{"type":"string","enum":["clubs:read","clubs:members:read","users:read","clubs:leaders:write","user-rewards:read","vector:ingest","article-drafts:read","article-drafts:write","leads:read","lead-matching:read","user-product:write","user-rewards:write"]},"maxItems":12,"description":"Exact operation grants. Managed keys receive no implicit permissions."},"expiresAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true}},"minProperties":1,"additionalProperties":false}}}},"security":[{"cookieAuth":[]},{"bearerAuth":[]}]},"delete":{"operationId":"delete-keys-by-id","summary":"Delete API key by ID","tags":["keys"],"responses":{"200":{"description":"Deletion acknowledgement.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}},"required":["id","deleted"],"additionalProperties":false,"example":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","deleted":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"e2a84f32-5ed5-48f8-ab32-5c4a7858fc67","deleted":true},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/clubs":{"get":{"operationId":"get-clubs","summary":"List clubs","description":"Pagination defaults to limit=100 and offset=0; count/skip are deprecated aliases. The maximum limit/count is 500. Responses are not cacheable.","tags":["clubs"],"responses":{"200":{"description":"Club collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyWpId":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"territories":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"coverPhotoUrl":{"type":["string","null"],"format":"uri"},"logoUrl":{"type":["string","null"],"format":"uri"},"color":{"type":["string","null"]},"clubLink":{"type":["string","null"],"format":"uri"}},"required":["id","legacyWpId","slug","name","territories"],"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/clubs/{id}":{"get":{"operationId":"get-clubs-by-id","summary":"Get club","tags":["clubs"],"responses":{"200":{"description":"Club response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyWpId":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"territories":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"coverPhotoUrl":{"type":["string","null"],"format":"uri"},"logoUrl":{"type":["string","null"],"format":"uri"},"color":{"type":["string","null"]},"clubLink":{"type":["string","null"],"format":"uri"}},"required":["id","legacyWpId","slug","name","territories"],"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."}]},"put":{"operationId":"put-clubs-by-id","summary":"Update club","description":"Requires an admin or a current leader of this club. Cookie-authenticated writes must send `Content-Type: application/json` and an `Origin` exactly matching the configured `AUTH_ISSUER_URL` origin (`https://auth.myltv.cloud` in production). Missing headers or a cross-site origin return `403 Forbidden`. OAuth bearer callers use `Authorization: Bearer ...` and are not subject to this cookie-session check. WordPress service credentials cannot update club metadata.","tags":["clubs"],"responses":{"200":{"description":"Updated club response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyWpId":{"type":"integer"},"slug":{"type":"string"},"name":{"type":"string"},"territories":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"coverPhotoUrl":{"type":["string","null"],"format":"uri"},"logoUrl":{"type":["string","null"],"format":"uri"},"color":{"type":["string","null"]},"clubLink":{"type":["string","null"],"format":"uri"}},"required":["id","legacyWpId","slug","name","territories"],"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","legacyWpId":286,"slug":"carolina-ltvers","name":"Carolina LTV'ers","territories":["US-NC","US-SC"],"description":"Regional owners club serving North and South Carolina.","coverPhotoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/travelersclub-carolinaltvers-feature.jpg","logoUrl":"https://admin.myltv.cloud/wp-content/uploads/2016/12/Carolina-LTVers-Logo-Filled.png","color":"#ce93d8","clubLink":"https://www.facebook.com/groups/495256330836508/"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"territories":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"coverPhotoUrl":{"type":["string","null"],"format":"uri"},"logoUrl":{"type":["string","null"],"format":"uri"},"color":{"type":["string","null"]},"clubLink":{"type":["string","null"],"format":"uri"}},"additionalProperties":false}}}},"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/clubs/{id}/members":{"get":{"operationId":"get-clubs-by-id-members","summary":"Get club members","description":"Private full-member records: requires an admin, a current leader of this club, or a managed service API key supplied with `X-ApiKey` and an explicit `clubs:members:read` grant. The deprecated `X-WordPress-Service-Key` remains accepted during migration. This is not the ordinary member-facing directory; use `GET /clubs/{id}/directory` for current club members. Pagination defaults to limit=100 and offset=0; count/skip are deprecated aliases. The maximum limit/count is 500. Responses are not cacheable.","tags":["clubs"],"responses":{"200":{"description":"Club members response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":true,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"description":"Private member details, available only to authorized club leaders, admins and scoped member readers."}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]},{"managedApiKey":[]},{"wordpressServiceKey":[]}]}},"/clubs/{id}/members/search":{"get":{"operationId":"get-clubs-by-id-members-search","summary":"Search club members","description":"Private full-member search: requires an admin or a current leader of this club. WordPress service credentials cannot search members. Ordinary members must use `GET /clubs/{id}/directory`; this endpoint is not consent-filtered. Pagination defaults to limit=100 and offset=0; count/skip are deprecated aliases. The maximum limit/count is 500. Responses are not cacheable.","tags":["clubs"],"responses":{"200":{"description":"Club member search response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":true,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"description":"Private member details, available only to authorized club leaders, admins and scoped member readers."}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."},{"name":"search","in":"query","required":true,"schema":{"type":"string","minLength":1}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated search fields. Defaults to email,firstName,lastName."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/clubs/{id}/directory":{"get":{"operationId":"get-clubs-by-id-directory","summary":"Get club member directory","description":"Member-facing directory: requires a current member of this club, or an admin. WordPress service credentials and API keys are not accepted. Responses are consent-filtered to verified members whose settings.shareContactDetails is exactly withTC or withAll, including consenting leaders. Filtering precedes pagination and counting. Cards are an explicit scalar allowlist and never full user records. This endpoint accepts pagination only; ordinary-member search must filter these bounded cards or use a separate member-facing search contract. Pagination defaults to limit=100 and offset=0; count/skip are deprecated aliases. The maximum limit/count is 500. Responses are not cacheable.","tags":["clubs"],"responses":{"200":{"description":"Club member directory response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","description":"Verified club member with exact withTC or withAll sharing consent. Bounded allowlist; unrelated clubs, credentials, VINs and street addresses are omitted.","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true,"nullable":true},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"email":{"type":["string","null"],"format":"email"},"verified":{"type":"boolean"},"address":{"type":"object","properties":{"city":{"type":["string","null"]},"state":{"type":["string","null"]},"country":{"type":["string","null"]},"lat":{"type":["string","number","null"]},"lng":{"type":["string","number","null"]}},"required":["city","state","country","lat","lng"],"additionalProperties":false},"profile":{"type":"object","properties":{"avatar":{"type":["string","null"]},"bio":{"type":["string","null"]},"phone":{"type":["string","null"]},"facebook":{"type":["string","null"]},"twitter":{"type":["string","null"]},"instagram":{"type":["string","null"]},"website":{"type":["string","null"]},"isExplorer":{"type":["boolean","null"]}},"required":["avatar","bio","phone","facebook","twitter","instagram","website","isExplorer"],"additionalProperties":false},"product":{"type":"object","properties":{"model":{"type":["string","null"]}},"required":["model"],"additionalProperties":false},"currentLocation":{"type":"object","properties":{"lat":{"type":["string","number","null"]},"lng":{"type":["string","number","null"]},"lastUpdated":{"type":["string","number","null"]}},"required":["lat","lng","lastUpdated"],"additionalProperties":false},"settings":{"type":"object","properties":{"shareContactDetails":{"type":["string","null"],"enum":["withTC","withAll",null]}},"required":["shareContactDetails"],"additionalProperties":false},"club":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"joinDate":{"type":["string","number","null"],"format":"date-time"},"isLeader":{"type":"boolean"}},"required":["id","slug","name","joinDate","isLeader"],"additionalProperties":false},"minItems":1,"maxItems":1},"primaryClubId":{"type":"string","format":"uuid","nullable":true},"primaryClub":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"joinDate":{"type":["string","number","null"],"format":"date-time"},"isLeader":{"type":"boolean"}},"required":["id","slug","name","joinDate","isLeader"],"additionalProperties":false,"nullable":true}},"required":["id","legacyId","firstName","lastName","email","verified","address","profile","product","currentLocation","settings","club","primaryClubId","primaryClub"],"additionalProperties":false,"example":{"id":"22222222-2222-4222-8222-222222222222","legacyId":"222222222222222222222222","firstName":"Casey","lastName":"Reid","email":"casey@example.com","verified":true,"address":{"city":"Winnipeg","state":"MB","country":"CA","lat":49.9,"lng":"-97.1"},"profile":{"avatar":null,"bio":null,"phone":null,"facebook":null,"twitter":null,"instagram":null,"website":null,"isExplorer":null},"product":{"model":"Unity"},"currentLocation":{"lat":null,"lng":null,"lastUpdated":null},"settings":{"shareContactDetails":"withTC"},"club":[{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"carolina-ltvers","name":"Carolina LTV'ers","joinDate":"2026-01-01T00:00:00.000Z","isLeader":false}],"primaryClubId":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","primaryClub":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"carolina-ltvers","name":"Carolina LTV'ers","joinDate":"2026-01-01T00:00:00.000Z","isLeader":false}}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":"22222222-2222-4222-8222-222222222222","legacyId":"222222222222222222222222","firstName":"Casey","lastName":"Reid","email":"casey@example.com","verified":true,"address":{"city":"Winnipeg","state":"MB","country":"CA","lat":49.9,"lng":"-97.1"},"profile":{"avatar":null,"bio":null,"phone":null,"facebook":null,"twitter":null,"instagram":null,"website":null,"isExplorer":null},"product":{"model":"Unity"},"currentLocation":{"lat":null,"lng":null,"lastUpdated":null},"settings":{"shareContactDetails":"withTC"},"club":[{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"carolina-ltvers","name":"Carolina LTV'ers","joinDate":"2026-01-01T00:00:00.000Z","isLeader":false}],"primaryClubId":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","primaryClub":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","slug":"carolina-ltvers","name":"Carolina LTV'ers","joinDate":"2026-01-01T00:00:00.000Z","isLeader":false}}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}],"security":[{"cookieAuth":[]},{"bearerAuth":[]}]}},"/clubs/{id}/coaches":{"get":{"operationId":"get-clubs-by-id-coaches","summary":"Get club coach count","tags":["clubs"],"responses":{"200":{"description":"Club coach count response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":["string","null"]},"uniqueCoaches":{"type":"integer","minimum":0}},"required":["success","message","uniqueCoaches"],"additionalProperties":false}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."}]}},"/clubs/{id}/leaders":{"get":{"operationId":"get-clubs-by-id-leaders","summary":"Get club leaders","description":"Public and ordinary-member responses contain bounded leader names, IDs, avatars and contact details because club leadership defaults to public sharing; ordinary member sharing consent does not gate leaders. Filtering precedes pagination and counting. Admins and current leaders of this club receive private member details. WordPress service credentials are not accepted. Pagination defaults to limit=100 and offset=0; count/skip are deprecated aliases. The maximum limit/count is 500. Responses are not cacheable.","tags":["clubs"],"responses":{"200":{"description":"Club leaders response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"profile":{"type":"object","properties":{"avatar":{"type":["string","null"]},"phone":{"type":["string","null"]}},"required":["avatar","phone"],"additionalProperties":false}},"required":["id","firstName","lastName","email","profile"],"additionalProperties":false,"example":{"id":"14ba0c2d-27f9-4de1-927c-4d8d6da5480a","firstName":"Casey","lastName":"Reid","email":"casey.reid@example.com","profile":{"avatar":null,"phone":null}}},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"legacyId":{"type":"string","deprecated":true},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["user","admin","club_leader","explorer"]},"verified":{"type":"boolean"},"primaryClubId":{"type":"string","format":"uuid","nullable":true,"readOnly":true},"primaryClub":{"type":"object","nullable":true,"readOnly":true,"description":"Explicit primary membership; null does not imply absence of other memberships.","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"joinDate":{"type":"string","format":"date-time","nullable":true},"isLeader":{"type":"boolean"}},"required":["id","slug","isLeader"]},"profile":{"type":"object","nullable":true,"description":"Stored profile JSON (avatar, bio, social links, coachNickname, etc.).","properties":{"coachNickname":{"type":"string","nullable":true,"maxLength":80,"description":"Optional coach moniker (boat-style nickname)."},"avatar":{"type":"string","nullable":true},"bio":{"type":"string","nullable":true}},"additionalProperties":true}},"required":["id","email"],"additionalProperties":true,"example":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","legacyId":"65a7e9b3a0f3f4c2d7b7e112","firstName":"Josiah","lastName":"Wiebe","email":"josiah@example.com","role":"user","verified":true,"profile":{"coachNickname":"Rolling Zephyr"}},"description":"Private member details, available only to authorized club leaders, admins and scoped member readers."}]}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/clubs/{id}/leaders/{leaderId}":{"put":{"operationId":"put-clubs-by-id-leaders-by-leaderId","summary":"Update club leader status","description":"Requires an admin, a current leader of this club, or a managed service API key with the explicit clubs:leaders:write grant. The deprecated WordPress service credential remains accepted during migration. The target must already belong to this club. Promotion returns 409 if the target is not a current member. A user may lead multiple clubs; this operation changes only the selected club and preserves other leadership and the explicit primary club. Cookie-authenticated writes require same-origin JSON.","tags":["clubs"],"responses":{"200":{"description":"Club leader status update response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"User owner@example.com has been promoted to a club leader for carolina-ltvers"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Target is not a current club member or already leads a different club.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical club UUID, slug or numeric legacy WordPress ID."},{"name":"leaderId","in":"path","required":true,"schema":{"type":"string"},"description":"Canonical user UUID or legacy Mongo user ID."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"isLeader":{"type":"boolean"}},"required":["isLeader"],"additionalProperties":false}}}},"security":[{"cookieAuth":[]},{"bearerAuth":[]},{"managedApiKey":[]},{"wordpressServiceKey":[]}]}},"/search/vector":{"post":{"operationId":"post-search-vector","summary":"Semantic vector search","tags":["search"],"responses":{"200":{"description":"Vector search response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"query":{"type":"string"},"topK":{"type":"integer"},"topKMode":{"type":"string","enum":["per-group"]},"groupCount":{"type":"integer"},"partialErrors":{"type":"array","items":{"type":"object","properties":{"filters":{"type":"object"},"status":{"type":"integer"},"message":{"type":"string"}}}},"count":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"content":{"type":"string"},"sourceId":{"type":"string"},"sourceName":{"type":"string"},"sourceChannelName":{"type":"string"},"sourceUrl":{"type":"string"},"canonicalUrl":{"type":"string"},"similarity":{"type":"number"}},"required":["id","content","sourceId","sourceUrl","canonicalUrl","similarity"]}}},"required":["query","topK","count","results"]},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","minLength":1,"maxLength":2000},"topK":{"type":"integer","minimum":1,"maximum":25},"minSimilarity":{"type":"number","minimum":0,"maximum":1},"filterCombos":{"type":"array","minItems":1,"maxItems":8,"description":"Search multiple groups with one embedding. topK applies per unique group.","items":{"type":"object","properties":{"sourceType":{"type":"string"},"contentType":{"type":"string"}},"anyOf":[{"required":["sourceType"]},{"required":["contentType"]}]}},"filters":{"type":"object","properties":{"sourceType":{"type":"string"},"ingestInterface":{"type":"string"},"contentType":{"type":"string"},"sourceId":{"type":"string"},"sourceChannelId":{"type":"string"},"publishedAfter":{"type":"string","format":"date-time"},"publishedBefore":{"type":"string","format":"date-time"}}}},"required":["query"],"additionalProperties":false}}}}}},"/search/ingest":{"post":{"operationId":"post-search-ingest","summary":"Run multi-interface content ingestion","tags":["search"],"responses":{"202":{"description":"Ingestion dispatch response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ingestInterface":{"type":"string","enum":["youtube-api","internal-api","wp-webhook","manual"],"description":"Ingestion interface used to discover items. internal-api reads from Order API MyLTV endpoints and is a management interface, not the content origin. Defaults to youtube-api."},"videoIds":{"type":"array","items":{"type":"string"},"description":"youtube-api only: explicit YouTube video IDs."},"channelIds":{"type":"array","items":{"type":"string"},"description":"youtube-api only: channel IDs or @handles to ingest."},"playlistId":{"type":"string","description":"youtube-api only: YouTube playlist ID (e.g. PLxxxx)."},"youtubeUrl":{"type":"string","description":"youtube-api only: YouTube video or playlist URL."},"internalItemIds":{"type":"array","items":{"type":"string"},"description":"internal-api only: explicit typed item IDs (myltv_article:<id>, myltv_video:<id>, myltv_component:<id>, myltv_ltvmanual:<id>, myltv_recall:<id>, myltv_component_manual:<componentId>:<manualId>)."},"internalCollectionId":{"type":"string","enum":["articles","videos","components","ltvmanuals","recalls","all"],"description":"internal-api only: MyLTV collection to ingest."},"maxItems":{"type":"integer","minimum":1,"maximum":1000,"description":"internal-api only limit."},"maxVideosPerChannel":{"type":"integer","minimum":1,"maximum":500,"description":"youtube-api only per-channel cap."}},"additionalProperties":false}}}}}},"/search/ingest/runs":{"get":{"operationId":"get-search-ingest-runs","summary":"List ingestion runs","tags":["search"],"responses":{"200":{"description":"Run history response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"itemsProcessed":{"type":"integer","minimum":0},"itemsSucceeded":{"type":"integer","minimum":0},"itemsFailed":{"type":"integer","minimum":0},"progress":{"type":"object","properties":{"requestedItemCount":{"type":"integer","minimum":0},"processedItemCount":{"type":"integer","minimum":0},"progressPct":{"type":["integer","null"],"minimum":0,"maximum":100}},"required":["requestedItemCount","processedItemCount","progressPct"],"additionalProperties":false}},"required":["id","status","itemsProcessed","itemsSucceeded","itemsFailed","progress"],"additionalProperties":true}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/search/ingest/indexed-sources":{"get":{"operationId":"get-search-ingest-indexed-sources","summary":"List indexed source IDs","tags":["search"],"responses":{"200":{"description":"Indexed source IDs response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"count":{"type":"integer","minimum":0},"sourceIds":{"type":"array","items":{"type":"string"}}},"required":["count","sourceIds"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"sourceType","in":"query","required":false,"schema":{"type":"string"}}]}},"/search/ingest/delete-sources":{"post":{"operationId":"post-search-ingest-delete-sources","summary":"Delete indexed sources","tags":["search"],"responses":{"200":{"description":"Delete indexed sources response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"deletedCount":{"type":"integer","minimum":0}},"required":["deletedCount"],"additionalProperties":false},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceIds":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["sourceIds"],"additionalProperties":false}}}}}},"/search/provider/status":{"get":{"operationId":"get-search-provider-status","summary":"Get external search provider status","tags":["search"],"responses":{"200":{"description":"Search provider status response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string"},"enabled":{"type":"boolean"}},"required":["provider","enabled"]},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/search/provider/sync":{"post":{"operationId":"post-search-provider-sync","summary":"Sync source documents to external search provider","tags":["search"],"responses":{"200":{"description":"Provider sync response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceIds":{"type":"array","items":{"type":"string"},"minItems":1}},"required":["sourceIds"],"additionalProperties":false}}}}}},"/search/ingest/wp":{"post":{"operationId":"post-search-ingest-wp","summary":"Queue one WordPress webhook content item for ingestion","description":"Preferred caller authentication is a managed service API key in X-ApiKey with the exact vector:ingest operation grant. The retained legacy gate accepts an administrator or VECTOR_ADMIN_KEY in X-Vector-Admin-Key and additionally requires VECTOR_WP_WEBHOOK_SECRET in X-WP-Webhook-Secret when configured. These legacy values authenticate callers; they do not sign payloads or provide HMAC integrity. Managed vector ingestion requires neither legacy secret. Signed form-intake payloads use a separate signing contract.","tags":["search"],"responses":{"202":{"description":"WordPress webhook ingestion response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["upsert","delete"]},"id":{"oneOf":[{"type":"string"},{"type":"number"}]},"postType":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string"},"sourceUrl":{"type":"string"},"canonicalUrl":{"type":"string"},"sourceRecordUrl":{"type":"string"},"publishedAt":{"type":"string"},"relatedIds":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]}},"taxonomyTerms":{"type":"array","items":{"type":"string"}}},"required":["action","id"],"additionalProperties":false}}}}}},"/search/ingest/wp/batch":{"post":{"operationId":"post-search-ingest-wp-batch","summary":"Queue a batch of WordPress webhook content items for ingestion","description":"Preferred caller authentication is a managed service API key in X-ApiKey with the exact vector:ingest operation grant. The retained legacy gate accepts an administrator or VECTOR_ADMIN_KEY in X-Vector-Admin-Key and additionally requires VECTOR_WP_WEBHOOK_SECRET in X-WP-Webhook-Secret when configured. These are static caller credentials, not HMAC payload signatures. Managed vector ingestion requires neither legacy secret.","tags":["search"],"responses":{"202":{"description":"WordPress webhook batch ingestion response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","additionalProperties":true},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","minItems":1,"items":{"type":"object","properties":{"action":{"type":"string","enum":["upsert","delete"]},"id":{"oneOf":[{"type":"string"},{"type":"number"}]},"postType":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string"},"sourceUrl":{"type":"string"},"canonicalUrl":{"type":"string"},"sourceRecordUrl":{"type":"string"},"publishedAt":{"type":"string"},"relatedIds":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"number"}]}},"taxonomyTerms":{"type":"array","items":{"type":"string"}}},"required":["action","id"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}}}},"/":{"get":{"operationId":"get-root","summary":"Get API status","tags":["system"],"responses":{"200":{"description":"API healthcheck response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"runtime":{"type":"string","enum":["hono"]}},"required":["status","runtime"],"additionalProperties":false,"example":{"status":"ok","runtime":"hono"}},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{"status":"ok","runtime":"hono"},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned"]}},"/docs":{"get":{"operationId":"get-docs","summary":"Get API docs","tags":["system"],"responses":{"200":{"description":"Scalar API docs HTML page.","content":{"text/html":{"schema":{"type":"string","example":"<!doctype html>..."}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned"]}},"/openapi.json":{"get":{"operationId":"get-openapi.json","summary":"Get OpenAPI document","tags":["system"],"responses":{"200":{"description":"OpenAPI document response.","content":{"application/json":{"schema":{"type":"object","properties":{"openapi":{"type":"string"},"info":{"type":"object"},"paths":{"type":"object"}},"required":["openapi","info","paths"],"additionalProperties":true,"example":{"openapi":"3.1.0","info":{"title":"Leisure Travel Vans API","version":"2.0.0"},"paths":{}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned"]}},"/openapi.scalar.json":{"get":{"operationId":"get-openapi.scalar.json","summary":"Get Scalar OpenAPI document","tags":["system"],"responses":{"200":{"description":"Scalar OpenAPI document response.","content":{"application/json":{"schema":{"type":"object","properties":{"openapi":{"type":"string"},"info":{"type":"object"},"paths":{"type":"object"}},"required":["openapi","info","paths"],"additionalProperties":true,"example":{"openapi":"3.1.0","info":{"title":"Leisure Travel Vans API","version":"2.0.0"},"paths":{}}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/auth/verify/{token}":{"get":{"operationId":"get-auth-verify-by-token","summary":"Verify email (token in path)","description":"IdP convenience route: calls IdP auth route `verifyEmail` with the token. Registration emails typically use IdP’s own verify URL (`/api/auth/verify-email`, hidden in Scalar); this path supports legacy or custom links. With `return_to` or `redirect_uri` (deprecated), redirects on success/error with `auth_action=verify_email` query params. On success, domain `users.verified` is updated (`afterEmailVerification`).","tags":["auth"],"responses":{"200":{"description":"JSON success when no redirect target is supplied.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Your email has been verified successfully."}}}}},"302":{"description":"When `return_to` / `redirect_uri` is present and valid: redirect with `auth_status` and related query params."},"400":{"description":"Invalid or expired token, or missing token.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"description":"Server error during verification.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"return_to","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"description":"Safe in-app URL for redirect after verify (IdP allowlist)."},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"deprecated":true}]}},"/api/auth":{"get":{"operationId":"get-api-auth","summary":"IdP auth endpoint","tags":["auth"],"responses":{"200":{"description":"IdP handler response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/api/auth/*":{"get":{"operationId":"get-api-auth-*","summary":"IdP auth wildcard endpoint","tags":["auth"],"responses":{"200":{"description":"IdP wildcard handler response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/jwks":{"get":{"operationId":"get-jwks","summary":"Get OIDC JWKS","tags":["oidc"],"responses":{"200":{"description":"JWKS response.","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["keys"],"additionalProperties":false,"example":{"keys":[{"kty":"RSA","kid":"1","use":"sig","alg":"RS256"}]}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/.well-known/openid-configuration":{"get":{"operationId":"get-.well-known-openid-configuration","summary":"Get OIDC discovery document","tags":["oidc"],"responses":{"200":{"description":"OIDC discovery response.","content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"userinfo_endpoint":{"type":"string","format":"uri"},"jwks_uri":{"type":"string","format":"uri"}},"required":["issuer","authorization_endpoint","token_endpoint","userinfo_endpoint","jwks_uri"],"additionalProperties":true,"example":{"issuer":"https://api.leisurevans.com","authorization_endpoint":"https://api.leisurevans.com/oauth2/authorize","token_endpoint":"https://api.leisurevans.com/oauth2/token","userinfo_endpoint":"https://api.leisurevans.com/oauth2/userinfo","jwks_uri":"https://api.leisurevans.com/jwks"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/embedded/login":{"post":{"operationId":"post-oauth2-embedded-login","summary":"Login with embedded first-party form","description":"Authenticates a user from an embedded first-party login form and establishes the local auth session.\n\nUse this as step 1 of embedded SSO: login -> bootstrap-ticket -> bootstrap-session.\n\nFirst-party websites may persist the embedded-login session cookie for their own server-side API calls.","tags":["auth"],"responses":{"200":{"description":"Embedded login response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{"user":{"id":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"owner@example.com","role":"user","product":{"model":"Unity","floorplan":"U24MB","year":"2024","vin":"1A2BC3D4E5F678901"}},"userId":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0"}}}}},"400":{"description":"Validation error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"description":"Authentication failed response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"503":{"description":"Authentication service unavailable response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"error":{"type":"string"}},"required":["success","message","error"],"additionalProperties":false,"example":{"success":false,"message":"Authentication service unavailable","error":"AUTH_SERVICE_ERROR"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string"}},"required":["email","password"],"additionalProperties":false}}}}}},"/oauth2/reset-password":{"post":{"operationId":"post-oauth2-reset-password","summary":"OAuth reset password","description":"Completes password reset using reset token and new password. For browser flows, provide `return_to` as a query parameter to receive a redirect back to the application.","tags":["auth"],"responses":{"200":{"description":"Password reset completion response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Operation completed successfully."}}}}},"302":{"description":"Redirects to return_to/redirect_uri when a safe destination is supplied."},"400":{"description":"Password reset validation response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"return_to","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"description":"Safe in-app or allowlisted absolute URL used as the reset-link callback destination."},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"deprecated":true}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"password":{"type":"string"},"passwordConfirmation":{"type":"string"}},"required":["token","password","passwordConfirmation"],"additionalProperties":false}}}}}},"/oauth2/register":{"post":{"operationId":"post-oauth2-register","summary":"Register OAuth client","tags":["oauth2"],"responses":{"201":{"description":"Dynamic client registration response.","content":{"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}}},"required":["client_id","client_secret","client_name","redirect_uris"],"additionalProperties":true,"example":{"client_id":"ltv-web-client","client_secret":"secret_123","client_name":"MyLTV Web App","redirect_uris":["https://myltv.cloud/oauth/callback"]}}}}},"400":{"description":"Client metadata validation response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/client/{id}":{"get":{"operationId":"get-oauth2-client-by-id","summary":"Get OAuth client metadata","tags":["oauth2"],"responses":{"200":{"description":"OAuth client metadata response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{"client_id":"ltv-web-client","client_name":"MyLTV Web App"}}}}},"404":{"$ref":"#/components/responses/NotFound"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/oauth2/consent":{"post":{"operationId":"post-oauth2-consent","summary":"Submit OAuth consent decision","tags":["oauth2"],"responses":{"200":{"description":"OAuth consent response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Operation completed successfully."}}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/bootstrap-ticket":{"post":{"operationId":"post-oauth2-bootstrap-ticket","summary":"Issue one-time bootstrap ticket","description":"Creates a short-lived, one-time JWT ticket for cross-domain SSO bootstrap after embedded login.\n\nCall this after successful `/oauth2/embedded/login`, then exchange with `/oauth2/bootstrap-session`.","tags":["auth"],"responses":{"200":{"description":"Bootstrap ticket response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"ticket":{"type":"string"},"expiresIn":{"type":"integer"}},"required":["success","ticket","expiresIn"],"additionalProperties":false,"example":{"success":true,"ticket":"jwt-token","expiresIn":120}}}}},"401":{"description":"Unauthorized response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/bootstrap-session":{"get":{"operationId":"get-oauth2-bootstrap-session","summary":"Create session from bootstrap ticket","description":"Consumes a one-time bootstrap ticket and establishes the central IdP session.\n\nThis is the browser SSO handoff on the auth domain, not the canonical website-to-API credential.\n\nWhen `redirect_uri` is provided, responds with 302 redirect to that URI after session creation.","tags":["auth"],"responses":{"200":{"description":"Bootstrap session response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false,"example":{"success":true}}}}},"302":{"description":"Redirects to provided redirect_uri when present."},"400":{"description":"Invalid bootstrap ticket response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"ticket","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri"}}]}},"/oauth2/token":{"post":{"operationId":"post-oauth2-token","summary":"Exchange OAuth token","tags":["oauth2"],"responses":{"200":{"description":"OAuth token response.","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","minimum":1},"refresh_token":{"type":"string"},"id_token":{"type":["string","null"]},"scope":{"type":"string"}},"required":["access_token","token_type","expires_in","refresh_token","scope"],"additionalProperties":false,"example":{"access_token":"at_123","token_type":"Bearer","expires_in":1209600,"refresh_token":"rt_123","id_token":null,"scope":"openid profile email"}}}}},"400":{"description":"OAuth grant validation response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"description":"OAuth client authentication response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/userinfo":{"get":{"operationId":"get-oauth2-userinfo","summary":"Get OIDC userinfo","tags":["auth"],"responses":{"200":{"description":"OIDC user profile response.","content":{"application/json":{"schema":{"type":"object","properties":{"sub":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"email_verified":{"type":"boolean"},"name":{"type":"string"},"given_name":{"type":"string"},"family_name":{"type":"string"}},"additionalProperties":true,"example":{"sub":"9b7a3e18-9eaf-4e0c-97f7-2f5b59a8f6c0","email":"owner@example.com","email_verified":true,"name":"Avery Morgan","given_name":"Avery","family_name":"Morgan","myltv_user_id":"3f2e1d0c-9b8a-7654-3210-fedcba987654","myltv_role":"user","myltv_product":{"model":"Unity","floorplan":"FX","year":"2026","vin":null},"myltv_profile":{"first_name":"Avery","last_name":"Morgan","display_name":"Avery Morgan","avatar":"https://cdn.example.com/avatars/avery.png","coach_nickname":"Rolling Zephyr","product":{"model":"Unity","floorplan":"FX","year":"2026","vin":null},"club":null,"verified":true}}}}}},"401":{"description":"Token authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/revoke":{"post":{"operationId":"post-oauth2-revoke","summary":"Revoke OAuth token","tags":["oauth2"],"responses":{"200":{"description":"OAuth token revocation response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false,"example":{"success":true}}}}},"401":{"description":"Client authentication response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/introspect":{"post":{"operationId":"post-oauth2-introspect","summary":"Introspect OAuth token","tags":["oauth2"],"responses":{"200":{"description":"OAuth token introspection response.","content":{"application/json":{"schema":{"type":"object","properties":{"active":{"type":"boolean"},"client_id":{"type":"string"},"token_type":{"type":"string"},"scope":{"type":"string"},"exp":{"type":"integer"},"sub":{"type":"string"}},"required":["active"],"additionalProperties":true,"example":{"active":true,"client_id":"ltv-web-client","token_type":"access_token","scope":"openid profile email"}}}}},"401":{"description":"OAuth client authentication response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/admin/clients":{"get":{"operationId":"get-oauth2-admin-clients","summary":"List OAuth clients","tags":["oauth2"],"responses":{"200":{"description":"OAuth client list response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"oneOf":[{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"clientId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["first_party","third_party"]},"owner":{"type":"string"},"description":{"type":"string"},"redirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"postLogoutRedirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"isOidc":{"type":"boolean"}},"required":["id","clientId","name"],"additionalProperties":false,"example":{"id":"11a5f6ad-f046-4f07-a741-9afb62f8695c","clientId":"ltv-web-client","name":"MyLTV Web App","kind":"first_party","owner":"ltv-website-next","description":"Primary web OAuth client.","redirectUris":["https://myltv.cloud/oauth/callback"],"postLogoutRedirectUris":["https://myltv.cloud/log-in"],"isOidc":true}}},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"clientId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["first_party","third_party"]},"owner":{"type":"string"},"description":{"type":"string"},"redirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"postLogoutRedirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"isOidc":{"type":"boolean"}},"required":["id","clientId","name"],"additionalProperties":false,"example":{"id":"11a5f6ad-f046-4f07-a741-9afb62f8695c","clientId":"ltv-web-client","name":"MyLTV Web App","kind":"first_party","owner":"ltv-website-next","description":"Primary web OAuth client.","redirectUris":["https://myltv.cloud/oauth/callback"],"postLogoutRedirectUris":["https://myltv.cloud/log-in"],"isOidc":true}},{"type":"null"}]}},"required":["success","data"],"additionalProperties":false,"example":{"success":true,"data":[{"id":"11a5f6ad-f046-4f07-a741-9afb62f8695c","clientId":"ltv-web-client","name":"MyLTV Web App","kind":"first_party","owner":"ltv-website-next","description":"Primary web OAuth client.","redirectUris":["https://myltv.cloud/oauth/callback"],"postLogoutRedirectUris":["https://myltv.cloud/log-in"],"isOidc":true}]}}}}},"403":{"description":"Admin authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]},"post":{"operationId":"post-oauth2-admin-clients","summary":"Create OAuth client","tags":["oauth2"],"responses":{"201":{"description":"OAuth client creation response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"clientId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["first_party","third_party"]},"owner":{"type":"string"},"description":{"type":"string"},"redirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"postLogoutRedirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"isOidc":{"type":"boolean"}},"required":["id","clientId","name"],"additionalProperties":false,"example":{"id":"11a5f6ad-f046-4f07-a741-9afb62f8695c","clientId":"ltv-web-client","name":"MyLTV Web App","kind":"first_party","owner":"ltv-website-next","description":"Primary web OAuth client.","redirectUris":["https://myltv.cloud/oauth/callback"],"postLogoutRedirectUris":["https://myltv.cloud/log-in"],"isOidc":true}}},"required":["success","message","data"],"additionalProperties":false,"example":{"success":true,"message":"Client created successfully","data":{"id":"11a5f6ad-f046-4f07-a741-9afb62f8695c","clientId":"ltv-web-client","name":"MyLTV Web App","kind":"first_party","owner":"ltv-website-next","description":"Primary web OAuth client.","redirectUris":["https://myltv.cloud/oauth/callback"],"postLogoutRedirectUris":["https://myltv.cloud/log-in"],"isOidc":true}}}}}},"400":{"description":"Client metadata validation response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"403":{"description":"Admin authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["first_party","third_party"]},"owner":{"type":"string"},"description":{"type":"string"},"redirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"postLogoutRedirectUris":{"type":"array","items":{"type":"string","format":"uri"}}},"required":["name","redirectUris"],"additionalProperties":false}}}}}},"/oauth2/admin/clients/{clientId}":{"delete":{"operationId":"delete-oauth2-admin-clients-by-clientId","summary":"Delete OAuth client","tags":["oauth2"],"responses":{"200":{"description":"OAuth client deletion response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"],"additionalProperties":false,"example":{"success":true}}}}},"404":{"description":"Client not found response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"clientId","in":"path","required":true,"schema":{"type":"string"}}]}},"/oauth2/admin/tokens":{"get":{"operationId":"get-oauth2-admin-tokens","summary":"List active OAuth tokens","tags":["oauth2"],"responses":{"200":{"description":"Admin OAuth token list response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","additionalProperties":true}}},"required":["success","data"],"additionalProperties":false,"example":{"success":true,"data":[]}}}}},"403":{"description":"Admin authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/admin/revoke":{"post":{"operationId":"post-oauth2-admin-revoke","summary":"Revoke OAuth token as admin","tags":["oauth2"],"responses":{"200":{"description":"Admin revoke response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Operation completed successfully."}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"description":"Admin authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/admin/analytics":{"get":{"operationId":"get-oauth2-admin-analytics","summary":"Get OAuth analytics","tags":["oauth2"],"responses":{"200":{"description":"OAuth analytics response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"activeTokens":{"type":"integer","minimum":0},"totalClients":{"type":"integer","minimum":0},"clientStats":{"type":"array","items":{"type":"object","properties":{"clientName":{"type":"string"},"clientId":{"type":"string"},"tokenCount":{"type":"integer","minimum":0}},"required":["clientName","clientId","tokenCount"],"additionalProperties":false}}},"required":["activeTokens","totalClients","clientStats"],"additionalProperties":true}},"required":["success","data"],"additionalProperties":false,"example":{"success":true,"data":{"activeTokens":12,"totalClients":3,"clientStats":[{"clientName":"MyLTV Web App","clientId":"ltv-web-client","tokenCount":12}]}}}}}},"403":{"description":"Admin authorization response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/end-session":{"get":{"operationId":"get-oauth2-end-session","summary":"OAuth logout (browser)","description":"Browser-oriented logout endpoint. Clears the current auth session and token state, then optionally redirects when `post_logout_redirect_uri` is provided as a query parameter.","tags":["auth"],"responses":{"200":{"description":"Logout response for API clients.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"redirect_uri":{"type":["string","null"]}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Logged out successfully","redirect_uri":null}}}}},"500":{"description":"Logout error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"post_logout_redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri"}}]},"post":{"operationId":"post-oauth2-end-session","summary":"OAuth logout (API)","description":"Programmatic logout endpoint for API clients and SPAs. Uses the current session context and does not require a request body.","tags":["auth"],"responses":{"200":{"description":"Logout response for API clients.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"redirect_uri":{"type":["string","null"]}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"Logged out successfully","redirect_uri":null}}}}},"500":{"description":"Logout error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/authorize":{"get":{"operationId":"get-oauth2-authorize","summary":"Authorize OAuth request","tags":["oauth2"],"responses":{"302":{"description":"Redirects back to login or client callback with authorization code."},"400":{"description":"Authorization request validation response.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["error"],"additionalProperties":false,"example":{"error":"invalid_request","error_description":"Missing or invalid request parameters.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"]}},"/oauth2/forgot-password":{"post":{"operationId":"post-oauth2-forgot-password","summary":"OAuth request password reset","description":"Forwards to IdP auth route `POST /api/auth/request-password-reset` with the same `email`. Optional query `return_to` is passed as IdP `redirectTo` only when safe; invalid/untrusted absolute URLs are ignored. Does not reveal whether the address exists.","tags":["auth"],"responses":{"200":{"description":"Password reset email queued when the account exists.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"additionalProperties":false,"example":{"success":true,"message":"If an account with that email exists, a password reset link has been sent."}}}}},"400":{"description":"Validation error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"return_to","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"description":"Safe in-app or allowlisted absolute URL used as the reset-link callback destination."},{"name":"redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri-reference"},"deprecated":true,"description":"Deprecated alias for `return_to`."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}},"additionalProperties":false}}}}}},"/owners/videos":{"get":{"operationId":"get-owners-videos","summary":"List owner videos","tags":["owners"],"responses":{"200":{"description":"Owner video collection response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"}},"required":["id","title"],"additionalProperties":true,"example":{"id":3846135,"title":"2016 Unity Customer Walkthrough"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":3846135,"title":"2016 Unity Customer Walkthrough"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/owners/videos/{videoId}":{"get":{"operationId":"get-owners-videos-by-videoId","summary":"Get owner video","tags":["owners"],"responses":{"200":{"description":"Owner video response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"}},"required":["id","title"],"additionalProperties":true,"example":{"id":3846135,"title":"2016 Unity Customer Walkthrough"}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":3846135,"title":"2016 Unity Customer Walkthrough"}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"description":"Invalid video ID response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"videoId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}}]}},"/owners/verify/{vin}":{"get":{"operationId":"get-owners-verify-by-vin","summary":"Verify owner VIN","tags":["owners"],"responses":{"200":{"description":"VIN verification response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{"vin":"2B9MB3347NG001234","status":"active","model":"Unity","year":2024}}}}},"400":{"description":"Invalid VIN response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"500":{"description":"VIN verification error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"vin","in":"path","required":true,"schema":{"type":"string"}}]}},"/dealers/{dealerId}/inventory":{"get":{"operationId":"get-dealers-by-dealerId-inventory","summary":"Get dealer inventory","description":"Returns public dealer inventory from dealer.api.leisurevans.com.","tags":["dealers"],"responses":{"200":{"description":"Dealer public inventory.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"dealerId":{"type":"integer"},"locationId":{"type":"integer"},"stock":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"orderId":{"type":"integer"},"modelYear":{"type":"string"},"product":{"type":"string"},"model":{"type":"string"},"chassisType":{"type":"string"},"coachId":{"type":"string"},"vin":{"type":"string"},"showName":{"type":"string","nullable":true},"scheduleStatus":{"type":"string"},"orderDate":{"type":"string"},"onlineDate":{"type":"string","nullable":true},"offlineDate":{"type":"string","nullable":true},"readyToShipDate":{"type":"string","nullable":true},"estimatedShipDate":{"type":"string","nullable":true},"actualShipDate":{"type":"string","nullable":true},"expectedArrivalDate":{"type":"string","nullable":true},"msrp":{"type":"integer","minimum":0},"cabinetry":{"type":"string","nullable":true},"counter":{"type":"string","nullable":true},"exterior":{"type":"string","nullable":true},"leather":{"type":"string","nullable":true}},"required":["orderId","modelYear","product","model","chassisType","coachId","vin","scheduleStatus","orderDate","onlineDate","readyToShipDate","estimatedShipDate","actualShipDate","expectedArrivalDate","cabinetry","counter","exterior","leather"],"example":{"orderId":12345,"modelYear":"2026","product":"Unity","model":"U24TB","chassisType":"Mercedes-Benz Sprinter","coachId":"U24TB-12345","vin":"WDAPF4CC0G0000000","showName":"Unity Twin Bed","scheduleStatus":"dealer stock","orderDate":"2026-01-01T00:00:00.000Z","onlineDate":"2026-01-15T00:00:00.000Z","offlineDate":"2026-02-15T00:00:00.000Z","readyToShipDate":null,"estimatedShipDate":null,"actualShipDate":null,"expectedArrivalDate":null,"cabinetry":"Rift Oak","counter":"Concrete","exterior":"Graphite","leather":"Dove"}}},"incoming":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"orderId":{"type":"integer"},"modelYear":{"type":"string"},"product":{"type":"string"},"model":{"type":"string"},"chassisType":{"type":"string"},"coachId":{"type":"string"},"vin":{"type":"string"},"showName":{"type":"string","nullable":true},"scheduleStatus":{"type":"string"},"orderDate":{"type":"string"},"onlineDate":{"type":"string","nullable":true},"offlineDate":{"type":"string","nullable":true},"readyToShipDate":{"type":"string","nullable":true},"estimatedShipDate":{"type":"string","nullable":true},"actualShipDate":{"type":"string","nullable":true},"expectedArrivalDate":{"type":"string","nullable":true},"msrp":{"type":"integer","minimum":0},"cabinetry":{"type":"string","nullable":true},"counter":{"type":"string","nullable":true},"exterior":{"type":"string","nullable":true},"leather":{"type":"string","nullable":true}},"required":["orderId","modelYear","product","model","chassisType","coachId","vin","scheduleStatus","orderDate","onlineDate","readyToShipDate","estimatedShipDate","actualShipDate","expectedArrivalDate","cabinetry","counter","exterior","leather"],"example":{"orderId":12345,"modelYear":"2026","product":"Unity","model":"U24TB","chassisType":"Mercedes-Benz Sprinter","coachId":"U24TB-12345","vin":"WDAPF4CC0G0000000","showName":"Unity Twin Bed","scheduleStatus":"dealer stock","orderDate":"2026-01-01T00:00:00.000Z","onlineDate":"2026-01-15T00:00:00.000Z","offlineDate":"2026-02-15T00:00:00.000Z","readyToShipDate":null,"estimatedShipDate":null,"actualShipDate":null,"expectedArrivalDate":null,"cabinetry":"Rift Oak","counter":"Concrete","exterior":"Graphite","leather":"Dove"}}},"totals":{"type":"object","additionalProperties":false,"properties":{"stock":{"type":"integer","minimum":0},"incoming":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0}},"required":["stock","incoming","total"]}},"required":["dealerId","locationId","stock","incoming","totals"],"example":{"dealerId":123,"locationId":1,"stock":[{"orderId":12345,"modelYear":"2026","product":"Unity","model":"U24TB","chassisType":"Mercedes-Benz Sprinter","coachId":"U24TB-12345","vin":"WDAPF4CC0G0000000","showName":"Unity Twin Bed","scheduleStatus":"dealer stock","orderDate":"2026-01-01T00:00:00.000Z","onlineDate":"2026-01-15T00:00:00.000Z","offlineDate":"2026-02-15T00:00:00.000Z","readyToShipDate":null,"estimatedShipDate":null,"actualShipDate":null,"expectedArrivalDate":null,"cabinetry":"Rift Oak","counter":"Concrete","exterior":"Graphite","leather":"Dove"}],"incoming":[],"totals":{"stock":1,"incoming":0,"total":1}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"dealerId","in":"path","required":true,"schema":{"type":"string"}},{"name":"locationId","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Dealer location ID. Defaults to 1 upstream when omitted."}]}},"/dealers/{dealerId}/inventory/{orderId}":{"get":{"operationId":"get-dealers-by-dealerId-inventory-by-orderId","summary":"Get dealer inventory order","description":"Returns one public dealer inventory order from dealer.api.leisurevans.com, including public colours and sanitized option values.","tags":["dealers"],"responses":{"200":{"description":"Dealer public inventory order.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"orderId":{"type":"integer"},"modelYear":{"type":"string"},"product":{"type":"string"},"model":{"type":"string"},"chassisType":{"type":"string"},"coachId":{"type":"string"},"vin":{"type":"string"},"showName":{"type":"string","nullable":true},"scheduleStatus":{"type":"string"},"orderDate":{"type":"string"},"onlineDate":{"type":"string","nullable":true},"offlineDate":{"type":"string","nullable":true},"readyToShipDate":{"type":"string","nullable":true},"estimatedShipDate":{"type":"string","nullable":true},"actualShipDate":{"type":"string","nullable":true},"expectedArrivalDate":{"type":"string","nullable":true},"msrp":{"type":"integer","minimum":0},"cabinetry":{"type":"string","nullable":true},"counter":{"type":"string","nullable":true},"exterior":{"type":"string","nullable":true},"leather":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"value":{"type":"string"}},"required":["name","value"],"example":{"name":"Solar Package","value":"Selected"}}}},"required":["orderId","modelYear","product","model","chassisType","coachId","vin","scheduleStatus","orderDate","onlineDate","readyToShipDate","estimatedShipDate","actualShipDate","expectedArrivalDate","cabinetry","counter","exterior","leather","options"],"example":{"orderId":12345,"modelYear":"2026","product":"Unity","model":"U24TB","chassisType":"Mercedes-Benz Sprinter","coachId":"U24TB-12345","vin":"WDAPF4CC0G0000000","showName":"Unity Twin Bed","scheduleStatus":"dealer stock","orderDate":"2026-01-01T00:00:00.000Z","onlineDate":"2026-01-15T00:00:00.000Z","offlineDate":"2026-02-15T00:00:00.000Z","readyToShipDate":null,"estimatedShipDate":null,"actualShipDate":null,"expectedArrivalDate":null,"cabinetry":"Rift Oak","counter":"Concrete","exterior":"Graphite","leather":"Dove","options":[{"name":"Solar Package","value":"Selected"}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"Dealer or public inventory order not found.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"success":{"type":"boolean"},"message":{"type":"string"}},"required":["success","message"],"example":{"success":false,"message":"Inventory order not found."}}}}},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"dealerId","in":"path","required":true,"schema":{"type":"string"}},{"name":"orderId","in":"path","required":true,"schema":{"type":"integer","minimum":1}},{"name":"locationId","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Dealer location ID. Defaults to 1 upstream when omitted."}]}},"/order":{"get":{"operationId":"get-order","summary":"Get order by VIN","description":"Get order by VIN from Triple E Order API.","tags":["order"],"responses":{"200":{"description":"Order response.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"example":{"success":true,"error":"","count":1,"results":[{"order":{"orderId":12345,"orderDate":"2024-01-01"},"extension":{},"options":[{"orderId":12345,"orderItem":"1","name":"611-1123-1233","value":"2026 Unity TBX","groupCode":"601","msrp":12345,"dealerPrice":12345}],"properties":[{"orderId":12345,"name":"Cabinetry","type":"Decor","value":"White Oak"}]}]}}}}},"400":{"description":"Validation error response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"401":{"description":"Authentication failed response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["success","message"],"additionalProperties":false,"example":{"success":false,"message":"Request failed.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"503":{"description":"Authentication service unavailable response.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"error":{"type":"string"}},"required":["success","message","error"],"additionalProperties":false,"example":{"success":false,"message":"Authentication service unavailable","error":"AUTH_SERVICE_ERROR"}}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"vin","in":"query","required":true,"schema":{"type":"string"}}]}},"/order/report/{id}":{"get":{"operationId":"get-order-report-by-id","summary":"Get order report by ID","description":"Get MSRP PDF order report by ID from Triple E Order API.","tags":["order"],"responses":{"200":{"description":"Order report PDF.","title":"LTV_MSRP_99999.pdf","headers":{"Content-Type":{"schema":{"type":"string","enum":["application/pdf"]}},"Content-Disposition":{"schema":{"type":"string","format":"filename"},"example":"attachment; filename=\"LTV_MSRP_99999.pdf\""}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"id path parameter."}]}},"/myltv/articles/all":{"get":{"operationId":"get-myltv-articles-all","summary":"List MyLTV articles","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/categories/all":{"get":{"operationId":"get-myltv-categories-all","summary":"List MyLTV categories","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/components/all":{"get":{"operationId":"get-myltv-components-all","summary":"List MyLTV components","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/ltvmanuals/all":{"get":{"operationId":"get-myltv-ltvmanuals-all","summary":"List MyLTV ltvmanuals","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/products/all":{"get":{"operationId":"get-myltv-products-all","summary":"List MyLTV products","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/recalls":{"get":{"operationId":"get-myltv-recalls","summary":"List MyLTV recalls","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/videos/all":{"get":{"operationId":"get-myltv-videos-all","summary":"List MyLTV videos","description":"Set `paginate=true` to receive the standard paginated response. Without it, this compatibility route returns the raw upstream payload and forwards query parameters unchanged. Eligible non-VIN collections are reused across page offsets in Vercel Runtime Cache.","tags":["myltv"],"responses":{"200":{"description":"Standard paginated MyLTV collection returned when `paginate=true`.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"example":{"id":1}}},"meta":{"type":"object","properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1},"offset":{"type":"integer","minimum":0},"nextCursor":{"type":"integer","minimum":0,"nullable":true}},"required":["total","limit","offset","nextCursor"],"additionalProperties":false},"message":{"type":"string"},"requestId":{"type":"string","format":"uuid"}},"required":["data","meta","requestId"],"additionalProperties":false,"example":{"data":[{"id":1}],"meta":{"total":1,"limit":50,"offset":0,"nextCursor":null},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"paginate","in":"query","required":false,"schema":{"type":"boolean","enum":[true]},"description":"Explicitly enables local pagination. A bare `limit` remains an upstream compatibility query parameter."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"count","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":1,"maximum":250}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0}},{"name":"skip","in":"query","required":false,"deprecated":true,"schema":{"type":"integer","minimum":0}},{"name":"fields","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated top-level fields to retain when local pagination is enabled."},{"name":"reverse","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"Reverse the complete filtered collection before slicing when local pagination is enabled."}]}},"/myltv/videos/{id}":{"get":{"operationId":"get-myltv-videos-by-id","summary":"/myltv/videos/{id}","description":"Returns one MyLTV video.","tags":["myltv"],"responses":{"200":{"description":"MyLTV video.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"allOf":[{"type":"object","additionalProperties":true,"properties":{"id":{"type":"integer"},"title":{"type":"string","nullable":true},"link":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"lastUpdated":{"type":"string","nullable":true}},"required":["id"],"example":{"id":380,"title":"Video 380","link":"https://www.youtube.com/watch?v=abc123","description":"Video description.","lastUpdated":"2026-01-01T00:00:00Z"}},{"type":"object","properties":{"transcript":{"type":"object","additionalProperties":false,"properties":{"videoId":{"type":"integer"},"youtubeVideoId":{"type":"string"},"sourceUrl":{"type":"string"},"segments":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"text":{"type":"string"},"startSeconds":{"type":"integer","minimum":0},"endSeconds":{"type":"integer","minimum":1}},"required":["text","startSeconds","endSeconds"]}},"text":{"type":"string"}},"required":["videoId","youtubeVideoId","sourceUrl","segments","text"],"example":{"videoId":380,"youtubeVideoId":"abc123","sourceUrl":"https://www.youtube.com/watch?v=abc123","segments":[{"text":"First line.","startSeconds":0,"endSeconds":2}],"text":"First line."}}}}]},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":false,"example":{"data":{},"requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"Requested video cannot provide a transcript.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"502":{"description":"Upstream API or YouTube transcript service failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"x-source-file":"specs/registry.ts","x-api-versions":["unversioned","v1","v2"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"transcript","in":"query","required":false,"schema":{"type":"boolean"},"description":"Include the transcript payload."}]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"cookieAuth":{"type":"apiKey","in":"cookie","name":"myltv.session_token","description":"Better Auth session cookie. Production may prefix it with `__Secure-`; configured BETTER_AUTH_SESSION_COOKIE overrides the default name."},"managedApiKey":{"type":"apiKey","in":"header","name":"x-apikey","description":"Server-only managed API key with exact operation grants; legacy plaintext user keys retain audited dealer operations only."},"wordpressServiceKey":{"type":"apiKey","in":"header","name":"X-WordPress-Service-Key","description":"Server-only WordPress service credential for explicitly audited member-reader operations."}},"headers":{"XApiVersion":{"description":"Resolved API version for this request.","schema":{"type":"string","enum":["1","2"]}},"XDatabaseBackend":{"description":"Backend selected for this request.","schema":{"type":"string","enum":["mongodb","postgres"]}},"XIdTranslation":{"description":"Legacy MongoDB ObjectId translation behavior.","schema":{"type":"string","enum":["enabled","disabled"]}},"XRequestId":{"description":"Trace ID for correlating request and logs.","schema":{"type":"string","format":"uuid"}}},"schemas":{"ApiSuccessEnvelope":{"type":"object","properties":{"data":{"type":"object"},"requestId":{"type":"string","format":"uuid"}},"required":["data","requestId"],"additionalProperties":true},"ValidationIssueDetail":{"type":"object","properties":{"path":{"type":"string","description":"Path to the invalid field."},"message":{"type":"string","description":"Validation error message."},"expected":{"type":"string","description":"Expected value/type when available."}},"required":["path","message"],"additionalProperties":false},"ProblemDetails":{"type":"object","properties":{"type":{"type":"string","format":"uri-reference"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"instance":{"type":"string","format":"uri-reference"},"requestId":{"type":"string","format":"uuid"},"invalidParams":{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssueDetail"}},"expectedSchema":{"type":"object","additionalProperties":true,"description":"Expected request shape for correcting validation errors."}},"required":["title","status"],"additionalProperties":false}},"responses":{"BadRequest":{"description":"Invalid request payload or parameters.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"about:blank","title":"Invalid Request","status":400,"detail":"One or more request parameters are invalid.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8","invalidParams":[{"path":"example","message":"Expected string but received number","expected":"string"}],"expectedSchema":{"example":{"type":"string"}}}}}},"Unauthorized":{"description":"Unauthorized.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://api.leisurevans.com/problems/unauthorized","title":"Unauthorized","status":401,"detail":"Authentication is required to access this resource.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}},"Forbidden":{"description":"Forbidden.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://api.leisurevans.com/problems/forbidden","title":"Forbidden","status":403,"detail":"You do not have permission to access this resource.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}},"NotFound":{"description":"Not found.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://api.leisurevans.com/problems/not-found","title":"Not Found","status":404,"detail":"The requested resource could not be found.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}},"MethodNotAllowed":{"description":"Method not allowed.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://api.leisurevans.com/problems/method-not-allowed","title":"Method Not Allowed","status":405,"detail":"The HTTP method is not supported for this endpoint.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}},"InternalServerError":{"description":"Internal server error.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"},"example":{"type":"https://api.leisurevans.com/problems/internal-server-error","title":"Internal Server Error","status":500,"detail":"An unexpected server error occurred.","requestId":"0d8b5744-7544-4bb0-8f95-65be635315d8"}}}}}}}