{"openapi":"3.1.0","info":{"title":"UPC API","version":"1.0.0","description":"Versioned HTTP API for UPC content, search, live media, Bible tools, and authenticated user features."},"servers":[{"url":"/","description":"Current API host"}],"tags":[{"name":"System","description":"Service metadata and health checks."},{"name":"Home","description":"Mobile home screen content built from published, non-deleted content."},{"name":"Content","description":"Published, non-deleted articles and sermons, plus series and history."},{"name":"Catalog","description":"Unified discovery over published, non-deleted content."},{"name":"Contributors","description":"Contributor profiles and their published, non-deleted content."},{"name":"Events","description":"Published, non-deleted church events."},{"name":"Bulletin","description":"Visible church bulletin items."},{"name":"Search","description":"Keyword and semantic resource search over published, non-deleted content."},{"name":"Bible","description":"Bible metadata and explanation tools."},{"name":"Bookmarks","description":"Authenticated saved content."},{"name":"Account","description":"Authenticated user resources."},{"name":"Notifications","description":"Authenticated account notification preferences."}],"paths":{"/api/health":{"get":{"operationId":"getHealth","tags":["System"],"summary":"Check API health","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/api/v1/home":{"get":{"operationId":"getHome","tags":["Home"],"summary":"Get home screen content","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HomeResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/about":{"get":{"operationId":"getAbout","tags":["Content"],"summary":"List about questions and answers","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AboutItem"}}}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/history":{"get":{"operationId":"getHistory","tags":["Content"],"summary":"List church history items","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/HistoryItem"}}}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/live":{"get":{"operationId":"getLiveStatus","tags":["System"],"summary":"Get live stream status","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["live"],"properties":{"live":{"$ref":"#/components/schemas/LiveStatus"}}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/articles":{"get":{"operationId":"listArticles","tags":["Content"],"summary":"List published articles","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}},{"name":"search","in":"query","description":"Keyword search term.","schema":{"type":"string","maxLength":200}},{"name":"sort","in":"query","schema":{"type":"string","enum":["newest","oldest"],"default":"newest"}},{"name":"featured","in":"query","description":"When true, return only CMS-curated featured content in featured order.","schema":{"type":"boolean","default":false}},{"name":"series","in":"query","description":"Comma-separated list of series UUIDs.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/articles/{article}":{"get":{"operationId":"getArticle","tags":["Content"],"summary":"Get an article by slug","parameters":[{"name":"article","in":"path","required":true,"description":"Article slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Article"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/articles/{article}/bookmark":{"get":{"operationId":"getArticleBookmark","tags":["Bookmarks"],"summary":"Get article bookmark state","description":"Returns false for anonymous users and the saved state for authenticated users. Bookmark routes use content UUIDs, not slugs. Deleted content is treated as not found.","parameters":[{"name":"article","in":"path","required":true,"description":"Article UUID to inspect.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ArticleBookmarkStatus"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"addArticleBookmark","tags":["Bookmarks"],"summary":"Bookmark an article","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"article","in":"path","required":true,"description":"Article UUID to bookmark.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["articleId","bookmarked"],"properties":{"articleId":{"type":"string","format":"uuid"},"bookmarked":{"type":"boolean","const":true}}}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"removeArticleBookmark","tags":["Bookmarks"],"summary":"Remove an article bookmark","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"article","in":"path","required":true,"description":"Article UUID to unbookmark.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No content"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons":{"get":{"operationId":"listSermons","tags":["Content"],"summary":"List published sermons","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}},{"name":"search","in":"query","description":"Keyword search term.","schema":{"type":"string","maxLength":200}},{"name":"sort","in":"query","schema":{"type":"string","enum":["newest","oldest"],"default":"newest"}},{"name":"featured","in":"query","description":"When true, return only CMS-curated featured content in featured order.","schema":{"type":"boolean","default":false}},{"name":"series","in":"query","description":"Comma-separated list of series UUIDs.","schema":{"type":"string"}},{"name":"minDuration","in":"query","description":"Minimum audio duration in seconds.","schema":{"type":"integer","minimum":0}},{"name":"maxDuration","in":"query","description":"Maximum audio duration in seconds.","schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons/{sermon}":{"get":{"operationId":"getSermon","tags":["Content"],"summary":"Get a sermon by slug","parameters":[{"name":"sermon","in":"path","required":true,"description":"Sermon slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Sermon"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons/{sermon}/related-content":{"get":{"operationId":"getSermonRelatedContent","tags":["Content"],"summary":"List content related to a sermon","description":"Returns a mixed list of published sermons and articles ranked primarily by embedding similarity, with shared series and contributor used as ranking boosts and relational matches used as a fallback.","parameters":[{"name":"sermon","in":"path","required":true,"description":"Sermon slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum related content items to return.","schema":{"type":"integer","minimum":1,"maximum":12,"default":8}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RelatedContentItem"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons/{sermon}/bookmark":{"get":{"operationId":"getSermonBookmark","tags":["Bookmarks"],"summary":"Get sermon bookmark state","description":"Returns false for anonymous users and the saved state for authenticated users. Bookmark routes use content UUIDs, not slugs. Deleted content is treated as not found.","parameters":[{"name":"sermon","in":"path","required":true,"description":"Sermon UUID to inspect.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SermonBookmarkStatus"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"addSermonBookmark","tags":["Bookmarks"],"summary":"Bookmark a sermon","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"sermon","in":"path","required":true,"description":"Sermon UUID to bookmark.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["sermonId","bookmarked"],"properties":{"sermonId":{"type":"string","format":"uuid"},"bookmarked":{"type":"boolean","const":true}}}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"removeSermonBookmark","tags":["Bookmarks"],"summary":"Remove a sermon bookmark","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"sermon","in":"path","required":true,"description":"Sermon UUID to unbookmark.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No content"},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons-per-book":{"get":{"operationId":"listSermonsPerBook","tags":["Content"],"summary":"List Bible books with recent published sermon previews","description":"Returns every Bible book in canonical order. Books with no published sermons have a sermonCount of 0 and an empty sermons array.","parameters":[{"name":"limit","in":"query","description":"Maximum sermon previews to include for each book.","schema":{"type":"integer","minimum":1,"maximum":12,"default":4}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SermonsByBookSection"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/sermons-per-book/{book}":{"get":{"operationId":"listSermonsForBook","tags":["Content"],"summary":"List published sermons that use a Bible book","parameters":[{"name":"book","in":"path","required":true,"description":"Bible book slug, abbreviation, or canonical book order.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["book","data","pagination"],"properties":{"book":{"$ref":"#/components/schemas/BibleBook"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/series/{series}":{"get":{"operationId":"getSeries","tags":["Content"],"summary":"Get a series by slug","parameters":[{"name":"series","in":"path","required":true,"description":"Series slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum sermons and articles included in the preview. Contributors are returned as a distinct relationship list.","schema":{"type":"integer","minimum":1,"maximum":50,"default":12}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SeriesDetail"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/series/{series}/sermons":{"get":{"operationId":"listSeriesSermons","tags":["Content"],"summary":"List sermons in a series","parameters":[{"name":"series","in":"path","required":true,"description":"Series slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/series/{series}/articles":{"get":{"operationId":"listSeriesArticles","tags":["Content"],"summary":"List articles in a series","parameters":[{"name":"series","in":"path","required":true,"description":"Series slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/contributors":{"get":{"operationId":"listContributors","tags":["Contributors"],"summary":"List contributors with latest activity","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContributorActivity"}}}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/contributors/{contributor}":{"get":{"operationId":"getContributor","tags":["Contributors"],"summary":"Get a contributor by slug","parameters":[{"name":"contributor","in":"path","required":true,"description":"Contributor slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum sermons and articles included in the preview. Series are returned as a distinct relationship list.","schema":{"type":"integer","minimum":1,"maximum":50,"default":12}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ContributorDetail"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/contributors/{contributor}/sermons":{"get":{"operationId":"listContributorSermons","tags":["Contributors"],"summary":"List sermons by a contributor","parameters":[{"name":"contributor","in":"path","required":true,"description":"Contributor slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/contributors/{contributor}/articles":{"get":{"operationId":"listContributorArticles","tags":["Contributors"],"summary":"List articles by a contributor","parameters":[{"name":"contributor","in":"path","required":true,"description":"Contributor slug.","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/events":{"get":{"operationId":"listEvents","tags":["Events"],"summary":"List published events","parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}},{"name":"search","in":"query","description":"Keyword search term. Also accepts date phrases such as \"today\", \"last month\", \"this year\", \"Jan 2026\", or \"July 3rd\".","schema":{"type":"string","maxLength":200}},{"name":"from","in":"query","description":"Start date/time filter.","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","description":"End date/time filter.","schema":{"type":"string","format":"date-time"}},{"name":"types","in":"query","description":"Comma-separated event types.","schema":{"type":"string"}},{"name":"showPast","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/events/{event}":{"get":{"operationId":"getEvent","tags":["Events"],"summary":"Get an event by slug","parameters":[{"name":"event","in":"path","required":true,"description":"Event slug.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/events/{event}/rsvp":{"get":{"operationId":"getEventRsvp","tags":["Events"],"summary":"Get event RSVP state","description":"Returns RSVP counts for a published, non-deleted event. Authenticated requests also include the current user's response and first-name attendee previews by status.","parameters":[{"name":"event","in":"path","required":true,"description":"Event UUID to inspect.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EventRsvpInfo"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"setEventRsvp","tags":["Events"],"summary":"Set the current user's event RSVP","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"event","in":"path","required":true,"description":"Event UUID to RSVP to.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetEventRsvpRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/EventRsvpInfo"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"clearEventRsvp","tags":["Events"],"summary":"Clear the current user's event RSVP","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"event","in":"path","required":true,"description":"Event UUID to clear RSVP for.","schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No content"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/bulletin":{"get":{"operationId":"listBulletinItems","tags":["Bulletin"],"summary":"List visible bulletin items","description":"Returns published bulletin items whose start date has passed and whose end date has not passed, sorted by prominence descending.","parameters":[{"name":"limit","in":"query","description":"Maximum number of visible bulletin items to return.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BulletinItem"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/bulletin/{bulletin}":{"get":{"operationId":"getBulletinItem","tags":["Bulletin"],"summary":"Get a visible bulletin item by UUID","parameters":[{"name":"bulletin","in":"path","required":true,"description":"Bulletin item UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BulletinItem"}}}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/catalog":{"get":{"operationId":"getCatalog","tags":["Catalog"],"summary":"Search and browse the unified catalog","description":"Sermon and article title matches rank above body-only matches. Contributor results match contributor profile fields directly and can include contributors without published sermons or articles.","parameters":[{"name":"q","in":"query","description":"Search query. Alias: search.","schema":{"type":"string","maxLength":500}},{"name":"search","in":"query","description":"Search query alias.","schema":{"type":"string","maxLength":500}},{"name":"searchMode","in":"query","description":"Controls keyword and semantic matching. Semantic matching is only used for authenticated requests; anonymous hybrid searches fall back to keyword results.","schema":{"type":"string","enum":["keyword","semantic","hybrid"]}},{"name":"resultMode","in":"query","schema":{"type":"string","enum":["ranked","typePreview"]}},{"name":"types","in":"query","description":"Comma-separated types: sermon, article, contributor, series.","schema":{"type":"string"}},{"name":"from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"to","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/search":{"get":{"operationId":"searchResources","tags":["Search"],"summary":"Search mobile resources","description":"Searches published resources, ranking sermon and article title matches above body-only matches.","parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":500}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/ask":{"get":{"operationId":"askResources","tags":["Search"],"summary":"Search resources with semantic expansion","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":500}},{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SearchResult"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/bible/version":{"get":{"operationId":"getBibleVersion","tags":["Bible"],"summary":"Get Bible export/version metadata","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["bible"],"properties":{"bible":{"$ref":"#/components/schemas/BibleVersion"}}}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/bible/explain":{"post":{"operationId":"explainBiblePassage","tags":["Bible"],"summary":"Explain selected Bible verses","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BibleExplainRequest"}}}},"responses":{"200":{"description":"Streaming markdown explanation.","content":{"text/plain":{"schema":{"type":"string","description":"Markdown explanation streamed as UTF-8 text chunks."}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"503":{"description":"Explanation service unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/bible/sync":{"get":{"operationId":"getBibleSyncSnapshot","tags":["Bible"],"summary":"Get Bible bookmark and highlight sync changes","description":"Returns the authenticated user's Bible bookmark groups and highlights changed at or after the optional cursor, including soft-deleted rows for reconciliation.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"cursor","in":"query","description":"ISO date-time cursor previously returned by this endpoint.","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BibleSyncSnapshot"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"operationId":"applyBibleSync","tags":["Bible"],"summary":"Push Bible bookmark and highlight changes","description":"Applies local bookmark/highlight creates, updates, soft-deletes, and revivals, then returns server-side changes at or after the provided cursor.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BibleSyncRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/BibleSyncSnapshot"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/me":{"get":{"operationId":"getCurrentUser","tags":["Account"],"summary":"Get the current user","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/User"}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/notifications/preferences":{"get":{"operationId":"getNotificationPreferences","tags":["Notifications"],"summary":"Get notification preferences","description":"Returns every active notification category with the authenticated user's account-wide email and push choices. Missing preference rows are returned as disabled. Inactive categories are omitted.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationPreferenceCategory"}}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"put":{"operationId":"updateNotificationPreference","tags":["Notifications"],"summary":"Update notification preferences","description":"Atomically upserts either one account-wide category/channel preference or a batch of up to 100 unique preference mutations, then returns the complete active preference list. The single-mutation body remains supported for existing clients. Push preferences do not imply that the current device has OS permission or an active FCM registration.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateNotificationPreferencesRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/NotificationPreferenceCategory"}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Notification category not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/notifications/installations/current":{"put":{"operationId":"upsertCurrentPushInstallation","tags":["Notifications"],"summary":"Register the current push installation","description":"Upserts the authenticated user's current mobile app installation by Firebase Installation ID. Repeated registration refreshes the FCM token and moves an existing installation to the currently authenticated account without exposing the token in the response.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertPushInstallationRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PushInstallation"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"operationId":"revokeCurrentPushInstallation","tags":["Notifications"],"summary":"Revoke the current push installation","description":"Idempotently disables the authenticated user's matching app installation and clears its stored FCM token. A missing or already transferred installation returns revoked=false.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokePushInstallationRequest"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["revoked"],"properties":{"revoked":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/delete-user":{"post":{"operationId":"deleteCurrentUser","tags":["Account"],"summary":"Delete the current user","description":"Requests or completes email-verified deletion of the authenticated Better Auth user. Database cascades remove account-owned bookmarks, Bible saved data, event RSVPs, settings, sessions, and sign-in methods. Published content and audit history are retained.","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","description":"Current password. Use this to request a deletion verification email."},"token":{"type":"string","description":"Deletion confirmation token from the verification email. Use this to complete deletion."},"callbackURL":{"type":"string","description":"URL to redirect to after deletion when the verification email link is used."}}}}}},"responses":{"200":{"description":"Deletion request processed","content":{"application/json":{"schema":{"type":"object","required":["success","message"],"properties":{"success":{"type":"boolean"},"message":{"type":"string","enum":["Verification email sent","User deleted"]}}}}}},"400":{"description":"Invalid password, token, or stale session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/auth/delete-user/callback":{"get":{"operationId":"confirmCurrentUserDeletion","tags":["Account"],"summary":"Confirm account deletion from email","description":"Completes an email-verified account deletion using the one-time token in the deletion email. On success, the user row is deleted and account-owned rows cascade, then the browser is redirected to the validated callback URL.","parameters":[{"name":"token","in":"query","required":true,"description":"One-time account deletion token from the email.","schema":{"type":"string"}},{"name":"callbackURL","in":"query","required":false,"description":"Trusted URL to redirect to after successful deletion. Untrusted values are ignored.","schema":{"type":"string","format":"uri"}}],"responses":{"302":{"description":"Account deleted; redirects to the callback URL.","headers":{"Location":{"description":"Validated post-deletion redirect URL.","schema":{"type":"string","format":"uri"}}}},"400":{"description":"Invalid, expired, or already-used token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/library":{"get":{"operationId":"getLibrary","tags":["Account"],"summary":"Get the current user's saved library","security":[{"sessionCookie":[]},{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","description":"Maximum number of items to return.","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"cursor","in":"query","description":"Opaque cursor returned by the previous page.","schema":{"type":"string"}},{"name":"search","in":"query","description":"Keyword search term.","schema":{"type":"string","maxLength":200}},{"name":"types","in":"query","description":"Comma-separated saved library item types to include. When omitted, all library item types are returned.","schema":{"type":"string","example":"sermon,article"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/LibraryItem"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"securitySchemes":{"sessionCookie":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Authenticated Better Auth session cookie. Exact cookie names may vary by deployment configuration."},"bearerAuth":{"type":"http","scheme":"bearer","description":"Better Auth bearer token."}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}}}}},"Health":{"type":"object","required":["ok","service","timestamp"],"properties":{"ok":{"type":"boolean"},"service":{"type":"string","example":"api"},"timestamp":{"type":"string","format":"date-time"}}},"Pagination":{"type":"object","required":["nextCursor","hasMore"],"properties":{"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"}}},"File":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"url":{"type":["string","null"],"format":"uri"},"title":{"type":["string","null"]},"altText":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"durationSeconds":{"type":["integer","null"]},"sizeBytes":{"type":["integer","null"]},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"blurhash":{"type":["string","null"]},"originalFilename":{"type":"string"},"thumbnail":{"type":["object","null"]},"transcription":{"type":"array","items":{"type":"object"}}}},"Contributor":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"displayName":{"type":["string","null"]},"title":{"type":["string","null"]},"image":{"$ref":"#/components/schemas/File"}}},"ContributorActivity":{"allOf":[{"$ref":"#/components/schemas/Contributor"},{"type":"object","properties":{"latestContentAt":{"type":["string","null"],"format":"date-time"},"latestContentType":{"type":["string","null"],"enum":["sermon","article",null]},"latestContentTitle":{"type":["string","null"]},"latestContentSlug":{"type":["string","null"]}}}]},"ContributorDetail":{"allOf":[{"$ref":"#/components/schemas/Contributor"},{"type":"object","properties":{"bio":{"type":["string","null"]},"series":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"sermons":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"articles":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"pagination":{"type":"object","properties":{"sermons":{"$ref":"#/components/schemas/Pagination"},"articles":{"$ref":"#/components/schemas/Pagination"}}}}}]},"Series":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"body":{"type":["string","null"]},"image":{"$ref":"#/components/schemas/File"},"video":{"$ref":"#/components/schemas/File"}}},"SeriesDetail":{"allOf":[{"$ref":"#/components/schemas/Series"},{"type":"object","properties":{"contributors":{"type":"array","items":{"$ref":"#/components/schemas/Contributor"}},"sermons":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}},"articles":{"type":"array","items":{"$ref":"#/components/schemas/Article"}},"pagination":{"type":"object","properties":{"sermons":{"$ref":"#/components/schemas/Pagination"},"articles":{"$ref":"#/components/schemas/Pagination"}}}}}]},"Passage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"label":{"type":["string","null"]},"reference":{"type":"string"},"bookId":{"type":"integer"},"bookName":{"type":"string"},"chapterNo":{"type":"integer"},"verses":{"type":"array","items":{"type":"object","properties":{"verseId":{"type":"integer"},"verseNo":{"type":"integer"},"text":{"type":"string"}}}}}},"Sermon":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"date":{"type":"string"},"time":{"type":["string","null"]},"body":{"type":["string","null"]},"preacher":{"$ref":"#/components/schemas/Contributor"},"series":{"$ref":"#/components/schemas/Series"},"image":{"$ref":"#/components/schemas/File"},"audio":{"$ref":"#/components/schemas/File"},"video":{"$ref":"#/components/schemas/File"},"passages":{"type":"array","items":{"$ref":"#/components/schemas/Passage"}},"isBookmarked":{"type":"boolean"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"BibleBook":{"type":"object","required":["id","name","slug","bookOrder","testament"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"abbrev":{"type":["string","null"]},"slug":{"type":"string"},"bookOrder":{"type":"integer"},"testament":{"type":"string","enum":["old","new"]}}},"SermonsByBookSection":{"type":"object","required":["book","sermonCount","sermons"],"properties":{"book":{"$ref":"#/components/schemas/BibleBook"},"sermonCount":{"type":"integer"},"sermons":{"type":"array","items":{"$ref":"#/components/schemas/Sermon"}}}},"RelatedContentItem":{"oneOf":[{"type":"object","required":["type","item"],"properties":{"type":{"type":"string","enum":["sermon"]},"item":{"$ref":"#/components/schemas/Sermon"}}},{"type":"object","required":["type","item"],"properties":{"type":{"type":"string","enum":["article"]},"item":{"$ref":"#/components/schemas/Article"}}}]},"Article":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":["string","null"]},"body":{"type":["string","null"]},"publishDate":{"type":"string"},"author":{"$ref":"#/components/schemas/Contributor"},"series":{"$ref":"#/components/schemas/Series"},"image":{"$ref":"#/components/schemas/File"},"audio":{"$ref":"#/components/schemas/File"},"video":{"$ref":"#/components/schemas/File"},"passages":{"type":"array","items":{"$ref":"#/components/schemas/Passage"}},"isBookmarked":{"type":"boolean"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"Location":{"type":["object","null"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"address":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"zipCode":{"type":["string","null"]},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"mapUrl":{"type":["string","null"]},"image":{"$ref":"#/components/schemas/File"}}},"Event":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"body":{"type":["string","null"]},"startsAt":{"type":["string","null"],"format":"date-time"},"endsAt":{"type":["string","null"],"format":"date-time"},"isAllDay":{"type":"boolean"},"cost":{"type":"number"},"registrationUrl":{"type":["string","null"]},"eventType":{"type":["string","null"]},"location":{"$ref":"#/components/schemas/Location"},"image":{"$ref":"#/components/schemas/File"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"EventRsvpStatus":{"type":"string","enum":["going","maybe","not_going"]},"EventRsvpCounts":{"type":"object","required":["going","maybe","notGoing"],"properties":{"going":{"type":"integer","minimum":0},"maybe":{"type":"integer","minimum":0},"notGoing":{"type":"integer","minimum":0}}},"EventRsvpAttendee":{"type":"object","required":["userId","firstName","initial"],"properties":{"userId":{"type":"string"},"firstName":{"type":"string"},"initial":{"type":"string","minLength":1,"maxLength":1}}},"EventRsvpAttendees":{"type":"object","required":["going","maybe","notGoing"],"properties":{"going":{"type":"array","items":{"$ref":"#/components/schemas/EventRsvpAttendee"}},"maybe":{"type":"array","items":{"$ref":"#/components/schemas/EventRsvpAttendee"}},"notGoing":{"type":"array","items":{"$ref":"#/components/schemas/EventRsvpAttendee"}}}},"EventRsvpInfo":{"type":"object","required":["eventId","isAuthenticated","myStatus","counts","attendees","currentUser"],"properties":{"eventId":{"type":"string","format":"uuid"},"isAuthenticated":{"type":"boolean"},"myStatus":{"type":["string","null"],"enum":["going","maybe","not_going",null]},"counts":{"$ref":"#/components/schemas/EventRsvpCounts"},"attendees":{"$ref":"#/components/schemas/EventRsvpAttendees"},"currentUser":{"oneOf":[{"$ref":"#/components/schemas/EventRsvpAttendee"},{"type":"null"}]}}},"SetEventRsvpRequest":{"type":"object","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/EventRsvpStatus"}}},"NotificationPreferenceCategory":{"type":"object","required":["key","label","description","emailEnabled","pushEnabled"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"description":{"type":"string"},"emailEnabled":{"type":"boolean"},"pushEnabled":{"type":"boolean"}}},"UpdateNotificationPreferenceRequest":{"type":"object","required":["categoryKey","channel","enabled"],"properties":{"categoryKey":{"type":"string","minLength":1,"maxLength":100},"channel":{"type":"string","enum":["email","push"]},"enabled":{"type":"boolean"}}},"UpdateNotificationPreferencesRequest":{"oneOf":[{"$ref":"#/components/schemas/UpdateNotificationPreferenceRequest"},{"type":"object","required":["updates"],"properties":{"updates":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/UpdateNotificationPreferenceRequest"}}}}]},"PushInstallationIdentity":{"type":"object","required":["app","firebaseInstallationId"],"properties":{"app":{"type":"string","enum":["mobile"]},"firebaseInstallationId":{"type":"string","minLength":1,"maxLength":255}}},"UpsertPushInstallationRequest":{"allOf":[{"$ref":"#/components/schemas/PushInstallationIdentity"},{"type":"object","required":["platform","fcmToken"],"properties":{"platform":{"type":"string","enum":["ios","android"]},"fcmToken":{"type":"string","minLength":1,"maxLength":4096}}}]},"RevokePushInstallationRequest":{"allOf":[{"$ref":"#/components/schemas/PushInstallationIdentity"},{"type":"object","properties":{"reason":{"type":"string","enum":["logout","push_disabled"],"default":"logout"}}}]},"PushInstallation":{"type":"object","required":["id","app","platform","firebaseInstallationId","enabled","lastSeenAt","tokenUpdatedAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"app":{"type":"string","enum":["mobile"]},"platform":{"type":"string","enum":["ios","android"]},"firebaseInstallationId":{"type":"string"},"enabled":{"type":"boolean"},"lastSeenAt":{"type":"string","format":"date-time"},"tokenUpdatedAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"BulletinItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"message":{"type":"string"},"startsAt":{"type":["string","null"],"format":"date-time"},"endsAt":{"type":["string","null"],"format":"date-time"},"prominence":{"type":"integer","minimum":1,"maximum":100},"showInGlobalBanner":{"type":"boolean"},"linkUrl":{"type":["string","null"],"format":"uri"},"authorDisplayName":{"type":"string"},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}}},"AboutItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"question":{"type":"string"},"answer":{"type":"string"}}},"HistoryItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":["string","null"]},"date":{"type":"string"},"media":{"$ref":"#/components/schemas/File"}}},"LiveStatus":{"type":"object","properties":{"isLive":{"type":"boolean"},"status":{"type":"string"},"input":{"type":["object","null"]},"playback":{"type":["object","null"]}}},"HomeResponse":{"type":"object","properties":{"app":{"type":"object","properties":{"minimumSupportedVersion":{"type":"string"}}},"home":{"type":"object","properties":{"serviceTimes":{"type":"array","items":{"type":"object"}},"primaryLocation":{"$ref":"#/components/schemas/Location"},"nextEvents":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"nextEvent":{"anyOf":[{"$ref":"#/components/schemas/Event"},{"type":"null"}]},"latestSermon":{"anyOf":[{"$ref":"#/components/schemas/Sermon"},{"type":"null"}]},"latestArticle":{"anyOf":[{"$ref":"#/components/schemas/Article"},{"type":"null"}]},"live":{"$ref":"#/components/schemas/LiveStatus"}}}}},"SearchResult":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["sermon","article","event","contributor","series","bible","bible-book","bible-chapter"]},"title":{"type":"string"},"subtitle":{"type":["string","null"]},"slug":{"type":"string"},"href":{"type":"string"},"matchedBy":{"type":"string","enum":["keyword","meaning"]}}},"CatalogResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"mode":{"type":"string","enum":["overview","results"]},"filters":{"type":"object"},"summary":{"type":"object"},"sections":{"type":"array","items":{"type":"object"}},"results":{"type":"array","items":{"type":"object"}}}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"ArticleBookmarkStatus":{"type":"object","required":["articleId","bookmarked"],"properties":{"articleId":{"type":"string","format":"uuid"},"bookmarked":{"type":"boolean"}}},"SermonBookmarkStatus":{"type":"object","required":["sermonId","bookmarked"],"properties":{"sermonId":{"type":"string","format":"uuid"},"bookmarked":{"type":"boolean"}}},"BibleVersion":{"type":"object","properties":{"translation":{"type":"string","example":"KJV"},"schemaVersion":{"type":"integer"},"verseCount":{"type":"integer"},"exportTimestamp":{"type":["string","null"],"format":"date-time"}}},"BibleExplainRequest":{"type":"object","required":["bookId","chapterNo","selectedVerses"],"properties":{"bookId":{"type":"integer","minimum":1},"chapterNo":{"type":"integer","minimum":1},"selectedVerses":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"integer","minimum":1}}}},"BibleExplanation":{"type":"object","properties":{"reference":{"type":"string"},"explanation":{"type":"string","description":"Markdown explanation."}}},"BibleSyncBookmarkGroup":{"type":"object","required":["id","bookId","chapterNo","verseKey","verseNos","createdAt","updatedAt","deletedAt"],"properties":{"id":{"type":"integer"},"bookId":{"type":"integer","minimum":1},"chapterNo":{"type":"integer","minimum":1},"verseKey":{"type":"string","example":"1,3,5"},"verseNos":{"type":"array","items":{"type":"integer","minimum":1}},"note":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"BibleSyncHighlight":{"type":"object","required":["id","bookId","chapterNo","verseNo","color","createdAt","updatedAt","deletedAt"],"properties":{"id":{"type":"integer"},"bookId":{"type":"integer","minimum":1},"chapterNo":{"type":"integer","minimum":1},"verseNo":{"type":"integer","minimum":1},"color":{"type":"string","example":"yellow"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"BibleSyncSnapshot":{"type":"object","required":["cursor","serverTime","bookmarkGroups","highlights"],"properties":{"cursor":{"type":"string","format":"date-time"},"serverTime":{"type":"string","format":"date-time"},"bookmarkGroups":{"type":"array","items":{"$ref":"#/components/schemas/BibleSyncBookmarkGroup"}},"highlights":{"type":"array","items":{"$ref":"#/components/schemas/BibleSyncHighlight"}}}},"BibleSyncBookmarkGroupInput":{"type":"object","required":["bookId","chapterNo","verseNos"],"properties":{"id":{"type":["integer","null"]},"bookId":{"type":"integer","minimum":1},"chapterNo":{"type":"integer","minimum":1},"verseNos":{"type":"array","minItems":1,"maxItems":176,"items":{"type":"integer","minimum":1}},"note":{"type":["string","null"],"maxLength":10000},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"BibleSyncHighlightInput":{"type":"object","required":["bookId","chapterNo","verseNo"],"properties":{"id":{"type":["integer","null"]},"bookId":{"type":"integer","minimum":1},"chapterNo":{"type":"integer","minimum":1},"verseNo":{"type":"integer","minimum":1},"color":{"type":"string","default":"yellow","maxLength":32},"deletedAt":{"type":["string","null"],"format":"date-time"}}},"BibleSyncRequest":{"type":"object","properties":{"cursor":{"type":["string","null"],"format":"date-time"},"bookmarkGroups":{"type":"array","maxItems":500,"items":{"$ref":"#/components/schemas/BibleSyncBookmarkGroupInput"}},"highlights":{"type":"array","maxItems":2000,"items":{"$ref":"#/components/schemas/BibleSyncHighlightInput"}}}},"User":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"email":{"type":"string","format":"email"},"emailVerified":{"type":"boolean"},"image":{"type":["string","null"]},"phone":{"type":["string","null"]},"role":{"type":["string","null"]},"settings":{"type":"object","properties":{"mobileAppDebug":{"type":"boolean"}},"required":["mobileAppDebug"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"LibraryItem":{"type":"object","properties":{"key":{"type":"string"},"type":{"type":"string","enum":["sermon","article","bibleBookmark","bibleHighlight"]},"createdAt":{"type":"string","format":"date-time"},"item":{"anyOf":[{"$ref":"#/components/schemas/Sermon"},{"$ref":"#/components/schemas/Article"},{"type":"object"}]}}}}}}