{"openapi":"3.1.0","info":{"title":"Shah Walayat Foundation Public API","description":"Public endpoints for theswf.net — a UK registered charity (No: 1093750) and Islamic community centre.\n\n## Always Available\nPrayer times, news, events, charity projects, shop, locations, bookings, donations, announcements, and search are always publicly accessible with no authentication required.\n\n## Feature-Gated Endpoints\nSome endpoint groups (Radio, LMS, Ibadah, OMS) are only available when the corresponding feature is enabled. Call `GET /api/site-settings/public-features` to check which features are currently active. Feature-gated endpoints return 403 when the feature is not enabled.\n\n## Notes\n- All times are in Europe/London timezone unless stated otherwise.\n- Prayer times are mosque-announced (jamaat + start times), not calculated estimates.\n- Paginated endpoints accept `page` and `page_size` query parameters.\n- All endpoints return JSON. No authentication is required.","version":"2.0.0","contact":{"name":"Shah Walayat Foundation","url":"https://theswf.net"}},"externalDocs":{"description":"API Documentation","url":"https://theswf.net/developers"},"servers":[{"url":"https://theswf.net","description":"Production"}],"tags":[{"name":"Prayer Times","description":"Mosque-announced prayer and jamaat times for our locations"},{"name":"News","description":"Published news articles and categories"},{"name":"Events","description":"Community events, classes, and programs"},{"name":"Projects","description":"Charity projects and fundraising campaigns"},{"name":"Shop","description":"Community shop products"},{"name":"Locations","description":"Venues, rooms, and facilities"},{"name":"Bookings","description":"Room and hall booking availability"},{"name":"Donations","description":"Public donation statistics"},{"name":"Announcements","description":"Public announcements and website banners"},{"name":"Search","description":"Cross-content search across all public data"},{"name":"Site Settings","description":"Public feature flags and configuration"},{"name":"Radio","description":"Community radio — schedules, live sessions, and recordings. Feature-gated: requires \"radio\" in public_features."},{"name":"LMS","description":"Learning Management System — classes, categories, and certificate verification. Feature-gated: requires \"lms\" in public_features."},{"name":"Ibadah","description":"Worship and spiritual content — Quran, hadith, duas, readings, and campaigns. Feature-gated: requires \"ibadah\" in public_features."},{"name":"OMS","description":"Operations — community boards and public drives. Feature-gated: requires \"oms\" in public_features."}],"paths":{"/api/prayer-times":{"get":{"tags":["Prayer Times"],"summary":"List prayer time locations/configs","operationId":"listPrayerTimeLocations","responses":{"200":{"description":"List of locations with prayer-time configuration","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PrayerLocation"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/prayer-times/{location_slug}/today":{"get":{"tags":["Prayer Times"],"summary":"Get today's prayer times for a location","operationId":"getPrayerTimesToday","parameters":[{"name":"location_slug","in":"path","required":true,"description":"Location slug identifier","schema":{"type":"string"},"example":"al-jamia-al-zahra"}],"responses":{"200":{"description":"Prayer times for today","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrayerTimesDay"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/prayer-times/{location_slug}/date/{date}":{"get":{"tags":["Prayer Times"],"summary":"Get prayer times for a specific date","operationId":"getPrayerTimesByDate","parameters":[{"name":"location_slug","in":"path","required":true,"description":"Location slug identifier","schema":{"type":"string"},"example":"al-jamia-al-zahra"},{"name":"date","in":"path","required":true,"description":"Date in YYYY-MM-DD format","schema":{"type":"string","format":"date"},"example":"2026-01-19"}],"responses":{"200":{"description":"Prayer times for the specified date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrayerTimesDay"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/prayer-times/{location_slug}/month":{"get":{"tags":["Prayer Times"],"summary":"Get prayer times for a full month","operationId":"getPrayerTimesMonth","parameters":[{"name":"location_slug","in":"path","required":true,"description":"Location slug identifier","schema":{"type":"string"},"example":"al-jamia-al-zahra"},{"name":"year","in":"query","required":true,"description":"Year (e.g., 2026)","schema":{"type":"integer","minimum":2000,"maximum":2100},"example":2026},{"name":"month","in":"query","required":true,"description":"Month number 1-12","schema":{"type":"integer","minimum":1,"maximum":12},"example":1}],"responses":{"200":{"description":"Array of daily prayer times for the month","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PrayerTimesDay"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/prayer-times/{location_slug}/ramadan":{"get":{"tags":["Prayer Times"],"summary":"Get Ramadan timetable (includes suhoor/iftar/taraweeh)","operationId":"getRamadanTimetable","parameters":[{"name":"location_slug","in":"path","required":true,"description":"Location slug identifier","schema":{"type":"string"},"example":"al-jamia-al-zahra"},{"name":"year","in":"query","required":false,"description":"Year (defaults to current Ramadan timetable)","schema":{"type":"integer","minimum":2000,"maximum":2100},"example":2026}],"responses":{"200":{"description":"Ramadan timetable with suhoor/iftar times","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PrayerTimesDay"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/news":{"get":{"tags":["News"],"summary":"List published news/articles","operationId":"listNews","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"category_id","in":"query","required":false,"description":"Filter by category ID","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}},{"name":"featured","in":"query","required":false,"description":"Filter featured articles only","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Paginated list of articles","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/NewsArticle"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/news/slug/{slug}":{"get":{"tags":["News"],"summary":"Get a single article by slug","operationId":"getNewsBySlug","parameters":[{"name":"slug","in":"path","required":true,"description":"Article URL slug","schema":{"type":"string"},"example":"ramadan-announcement"}],"responses":{"200":{"description":"Article details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewsArticle"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/news/categories":{"get":{"tags":["News"],"summary":"List news categories","operationId":"listNewsCategories","responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/events":{"get":{"tags":["Events"],"summary":"List events (supports upcoming filter)","operationId":"listEvents","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"upcoming","in":"query","required":false,"description":"If true, return only upcoming events","schema":{"type":"boolean"}},{"name":"category","in":"query","required":false,"description":"Category filter (community, educational, charity, religious, youth)","schema":{"type":"string"}},{"name":"featured_only","in":"query","required":false,"description":"Filter featured events only","schema":{"type":"boolean"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of events","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/events/slug/{slug}":{"get":{"tags":["Events"],"summary":"Get event details by slug","operationId":"getEventBySlug","parameters":[{"name":"slug","in":"path","required":true,"description":"Event URL slug","schema":{"type":"string"},"example":"community-iftar"}],"responses":{"200":{"description":"Event details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/projects":{"get":{"tags":["Projects"],"summary":"List charity projects","operationId":"listProjects","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"category","in":"query","required":false,"description":"Category filter","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of projects","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Project"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/projects/featured":{"get":{"tags":["Projects"],"summary":"Get featured projects","operationId":"listFeaturedProjects","parameters":[{"name":"limit","in":"query","required":false,"description":"Number of projects","schema":{"type":"integer","minimum":1,"maximum":50,"default":5}}],"responses":{"200":{"description":"Featured projects","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/projects/slug/{slug}":{"get":{"tags":["Projects"],"summary":"Get a project by slug","operationId":"getProjectBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"orphan-sponsorship"}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/projects/{project_id}/stats":{"get":{"tags":["Projects"],"summary":"Get donation stats for a project","operationId":"getProjectStats","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Donation stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStats"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/shop":{"get":{"tags":["Shop"],"summary":"List shop products","operationId":"listShopItems","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"type","in":"query","required":false,"description":"Product type","schema":{"type":"string","enum":["physical","external","preorder","interest"]}},{"name":"category","in":"query","required":false,"description":"Category filter","schema":{"type":"string"}},{"name":"featured","in":"query","required":false,"description":"Featured only","schema":{"type":"boolean"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of shop items","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ShopItem"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/shop/{slug}":{"get":{"tags":["Shop"],"summary":"Get a shop product by slug","operationId":"getShopItemBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"prayer-mat"}],"responses":{"200":{"description":"Shop item details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopItem"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations":{"get":{"tags":["Locations"],"summary":"List active locations","operationId":"listLocations","responses":{"200":{"description":"List of locations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Location"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations/main":{"get":{"tags":["Locations"],"summary":"Get main mosque/centre details","operationId":"getMainLocation","responses":{"200":{"description":"Main location","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations/{slug}":{"get":{"tags":["Locations"],"summary":"Get a specific location by slug","operationId":"getLocationBySlug","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"al-jamia-al-zahra"}],"responses":{"200":{"description":"Location details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Location"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations/bookable":{"get":{"tags":["Locations"],"summary":"List locations with bookable rooms/halls","operationId":"listBookableLocations","responses":{"200":{"description":"Bookable locations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Location"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations/{slug}/bookable-units":{"get":{"tags":["Bookings"],"summary":"List bookable units for a location","operationId":"listBookableUnits","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"al-jamia-al-zahra"}],"responses":{"200":{"description":"Bookable units with facilities and rates","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BookableUnit"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/locations/{slug}/bookable-units/{unit_slug}":{"get":{"tags":["Bookings"],"summary":"Get details of a specific bookable unit","operationId":"getBookableUnit","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"},"example":"al-jamia-al-zahra"},{"name":"unit_slug","in":"path","required":true,"schema":{"type":"string"},"example":"main-hall"}],"responses":{"200":{"description":"Bookable unit details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookableUnit"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/bookings/availability":{"get":{"tags":["Bookings"],"summary":"Check availability for a bookable unit on a date","operationId":"getBookingAvailability","parameters":[{"name":"unit_id","in":"query","required":true,"description":"Bookable unit ID","schema":{"type":"string"}},{"name":"date","in":"query","required":true,"description":"Date (YYYY-MM-DD)","schema":{"type":"string","format":"date"}},{"name":"end","in":"query","required":false,"description":"End date for range (max 31 days)","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Available slots","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingAvailability"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/donations/stats":{"get":{"tags":["Donations"],"summary":"Public donation statistics (aggregated)","operationId":"getDonationStats","responses":{"200":{"description":"Donation stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DonationStats"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/announcements":{"get":{"tags":["Announcements"],"summary":"Get active public announcements","operationId":"listAnnouncements","responses":{"200":{"description":"Active announcements","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Announcement"}}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/special-announcements/website":{"get":{"tags":["Announcements"],"summary":"Get active website banner announcement","operationId":"getWebsiteAnnouncement","responses":{"200":{"description":"Active website announcement or null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebsiteAnnouncement"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/site-settings/public-features":{"get":{"tags":["Site Settings"],"summary":"List currently enabled public features","operationId":"listPublicFeatures","description":"Returns the list of feature flags that are publicly enabled. Use this to check if feature-gated endpoints (radio, lms, ibadah, oms) are available before calling them.","responses":{"200":{"description":"Array of enabled feature names","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"example":["lms","ibadah","radio"]}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/search":{"post":{"tags":["Search"],"summary":"Search across all public content","operationId":"search","description":"Searches news, events, projects, products, locations, and any enabled feature-gated content. No authentication required — returns results visible to anonymous users.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":1,"maxLength":200,"description":"Search query"},"category":{"type":"string","description":"Filter to a specific content category (e.g., news, events, projects)"},"limit":{"type":"integer","minimum":1,"maximum":10,"default":5,"description":"Max results per category"}}}}}},"responses":{"200":{"description":"Search results grouped by category","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/radio/schedules/upcoming":{"get":{"tags":["Radio"],"summary":"Get upcoming broadcast schedule (next 24h)","operationId":"getUpcomingRadioSchedules","x-feature-gate":"radio","responses":{"200":{"description":"Upcoming scheduled broadcasts","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RadioSchedule"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/radio/sessions/current":{"get":{"tags":["Radio"],"summary":"Get currently live radio session","operationId":"getCurrentRadioSession","x-feature-gate":"radio","responses":{"200":{"description":"Current live session or null if nothing is live","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RadioSession"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/radio/recordings/public":{"get":{"tags":["Radio"],"summary":"Browse past radio recordings","operationId":"listPublicRadioRecordings","x-feature-gate":"radio","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Paginated list of public recordings","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/RadioRecording"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/lms/classes/public":{"get":{"tags":["LMS"],"summary":"Browse available classes","operationId":"listPublicClasses","x-feature-gate":"lms","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"category_id","in":"query","required":false,"description":"Filter by category","schema":{"type":"string"}},{"name":"delivery_mode","in":"query","required":false,"description":"Filter by delivery mode","schema":{"type":"string","enum":["in_person","online","hybrid"]}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of public classes","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/LmsClass"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/lms/classes/public/{identifier}":{"get":{"tags":["LMS"],"summary":"Get class details by ID or slug","operationId":"getPublicClass","x-feature-gate":"lms","parameters":[{"name":"identifier","in":"path","required":true,"description":"Class ID or slug","schema":{"type":"string"}}],"responses":{"200":{"description":"Class details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LmsClassDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/lms/categories/public":{"get":{"tags":["LMS"],"summary":"List class categories","operationId":"listLmsCategories","x-feature-gate":"lms","responses":{"200":{"description":"List of LMS categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LmsCategory"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/lms/certificates/verify/{code}":{"get":{"tags":["LMS"],"summary":"Verify a certificate by code","operationId":"verifyCertificate","description":"Always public — does not require the LMS feature to be enabled.","parameters":[{"name":"code","in":"path","required":true,"description":"Certificate verification code","schema":{"type":"string"}}],"responses":{"200":{"description":"Certificate verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateVerification"}}}},"default":{"$ref":"#/components/responses/ErrorResponse"}}}},"/api/ibadah/duas/public/categories":{"get":{"tags":["Ibadah"],"summary":"List dua categories","operationId":"listDuaCategories","x-feature-gate":"ibadah","responses":{"200":{"description":"Dua categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DuaCategory"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/duas/public":{"get":{"tags":["Ibadah"],"summary":"Browse published duas","operationId":"listDuas","x-feature-gate":"ibadah","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"category_slug","in":"query","required":false,"description":"Filter by category slug","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of duas","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Dua"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/duas/public/{dua_id}":{"get":{"tags":["Ibadah"],"summary":"Get a single dua","operationId":"getDua","x-feature-gate":"ibadah","parameters":[{"name":"dua_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Dua details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dua"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/hadith/public/collections":{"get":{"tags":["Ibadah"],"summary":"List hadith collections","operationId":"listHadithCollections","x-feature-gate":"ibadah","responses":{"200":{"description":"Hadith collections","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HadithCollection"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/hadith/public/collections/{slug}":{"get":{"tags":["Ibadah"],"summary":"Get hadith collection with books","operationId":"getHadithCollection","x-feature-gate":"ibadah","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Collection with book list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HadithCollectionDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/hadith/public/collections/{slug}/books/{book_number}":{"get":{"tags":["Ibadah"],"summary":"List hadiths in a book","operationId":"listHadithsInBook","x-feature-gate":"ibadah","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"book_number","in":"path","required":true,"schema":{"type":"integer"}},{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Paginated hadiths","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Hadith"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/hadith/public/collections/{slug}/hadiths/{hadith_number}":{"get":{"tags":["Ibadah"],"summary":"Get a single hadith by number","operationId":"getHadith","x-feature-gate":"ibadah","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"hadith_number","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Hadith details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hadith"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/hadith/public/search":{"get":{"tags":["Ibadah"],"summary":"Search hadiths by English or Arabic text","operationId":"searchHadiths","x-feature-gate":"ibadah","parameters":[{"name":"q","in":"query","required":true,"description":"Search query (min 2 chars)","schema":{"type":"string","minLength":2}},{"name":"collection","in":"query","required":false,"description":"Filter by collection slug","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Matching hadiths","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Hadith"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/readings/public":{"get":{"tags":["Ibadah"],"summary":"Browse published readings (ziyarat, prayers, adhkar)","operationId":"listReadings","x-feature-gate":"ibadah","parameters":[{"name":"page","in":"query","required":false,"description":"Page number","schema":{"type":"integer","minimum":1,"default":1}},{"name":"page_size","in":"query","required":false,"description":"Items per page (max 50)","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"reading_type","in":"query","required":false,"description":"Filter by type","schema":{"type":"string"}},{"name":"search","in":"query","required":false,"description":"Free-text search query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated readings","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Reading"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/readings/public/{reading_id}":{"get":{"tags":["Ibadah"],"summary":"Get a single reading","operationId":"getReading","x-feature-gate":"ibadah","parameters":[{"name":"reading_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reading"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/quran/public/surahs":{"get":{"tags":["Ibadah"],"summary":"List all 114 surahs","operationId":"listSurahs","x-feature-gate":"ibadah","responses":{"200":{"description":"All surahs with metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Surah"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/quran/public/surahs/{number}":{"get":{"tags":["Ibadah"],"summary":"Get full surah with ayahs","operationId":"getSurah","x-feature-gate":"ibadah","parameters":[{"name":"number","in":"path","required":true,"description":"Surah number (1-114)","schema":{"type":"integer","minimum":1,"maximum":114}}],"responses":{"200":{"description":"Surah with ayahs and translations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurahDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/quran/public/pages/{page_number}":{"get":{"tags":["Ibadah"],"summary":"Get Mushaf page with word-level data","operationId":"getMushafPage","x-feature-gate":"ibadah","parameters":[{"name":"page_number","in":"path","required":true,"description":"Mushaf page (1-604)","schema":{"type":"integer","minimum":1,"maximum":604}}],"responses":{"200":{"description":"Mushaf page with lines and words","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MushafPage"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/quran/public/juz/{number}":{"get":{"tags":["Ibadah"],"summary":"Get all ayahs in a juz","operationId":"getJuz","x-feature-gate":"ibadah","parameters":[{"name":"number","in":"path","required":true,"description":"Juz number (1-30)","schema":{"type":"integer","minimum":1,"maximum":30}}],"responses":{"200":{"description":"Juz with ayahs grouped by surah","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JuzDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/campaigns/public":{"get":{"tags":["Ibadah"],"summary":"List active public campaigns","operationId":"listCampaigns","x-feature-gate":"ibadah","responses":{"200":{"description":"Active campaigns","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/campaigns/public/featured":{"get":{"tags":["Ibadah"],"summary":"Get the featured campaign","operationId":"getFeaturedCampaign","x-feature-gate":"ibadah","responses":{"200":{"description":"Featured campaign or null","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/campaigns/public/{campaign_id}":{"get":{"tags":["Ibadah"],"summary":"Get campaign detail with activities","operationId":"getCampaign","x-feature-gate":"ibadah","parameters":[{"name":"campaign_id","in":"path","required":true,"description":"Campaign ID or slug","schema":{"type":"string"}}],"responses":{"200":{"description":"Campaign with activities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/campaigns/public/{campaign_id}/contributors":{"get":{"tags":["Ibadah"],"summary":"Get per-activity contributor lists","operationId":"getCampaignContributors","x-feature-gate":"ibadah","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Contributors per activity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignContributors"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/ibadah/campaigns/public/{campaign_id}/breakdown":{"get":{"tags":["Ibadah"],"summary":"Get activity breakdown by time period","operationId":"getCampaignBreakdown","x-feature-gate":"ibadah","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"string"}},{"name":"period","in":"query","required":false,"description":"Period type","schema":{"type":"string","enum":["day","week","month"],"default":"week"}},{"name":"count","in":"query","required":false,"description":"Number of periods","schema":{"type":"integer","minimum":1,"maximum":52,"default":4}}],"responses":{"200":{"description":"Activity breakdown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignBreakdown"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/oms/boards/public":{"get":{"tags":["OMS"],"summary":"List published community boards","operationId":"listPublicBoards","x-feature-gate":"oms","parameters":[{"name":"category","in":"query","required":false,"description":"Filter by category (food, donation, help, general)","schema":{"type":"string"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"Paginated community boards","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CommunityBoard"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/oms/boards/public/{id_or_slug}":{"get":{"tags":["OMS"],"summary":"Get board detail with groups, slots, and pledges","operationId":"getPublicBoard","x-feature-gate":"oms","parameters":[{"name":"id_or_slug","in":"path","required":true,"description":"Board ID or slug","schema":{"type":"string"}}],"responses":{"200":{"description":"Board with full structure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommunityBoardDetail"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/oms/drives/public":{"get":{"tags":["OMS"],"summary":"List active volunteer drives","operationId":"listPublicDrives","x-feature-gate":"oms","parameters":[{"name":"type","in":"query","required":false,"description":"Drive type filter","schema":{"type":"string","enum":["recurring","one_off","open_ended"]}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"Paginated volunteer drives","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VolunteerDrive"}},"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"},"total_pages":{"type":"integer"}}}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}},"/api/oms/drives/public/{drive_id}":{"get":{"tags":["OMS"],"summary":"Get volunteer drive details","operationId":"getPublicDrive","x-feature-gate":"oms","parameters":[{"name":"drive_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Drive details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VolunteerDrive"}}}},"403":{"$ref":"#/components/responses/FeatureNotEnabled"}}}}},"components":{"responses":{"ErrorResponse":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"FeatureNotEnabled":{"description":"Feature not enabled — check GET /api/site-settings/public-features to see which features are currently active.","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"type":"string","example":"This feature is not publicly available"}}}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","example":"Bad Request"},"message":{"type":"string","example":"Invalid parameters"}}},"PrayerLocation":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string","example":"al-jamia-al-zahra"},"name":{"type":"string","example":"Al Jamia Al Zahra"},"address":{"type":"string","example":"18 Francis Street"},"city":{"type":"string","example":"Halifax"},"postcode":{"type":"string","example":"HX1 5JY"},"prayer_time_set_id":{"type":"string"},"prayer_time_set_name":{"type":"string"}}},"PrayerTimesDay":{"type":"object","description":"A single day's mosque-announced prayer times (start + jamaat)","properties":{"date":{"type":"string","format":"date","example":"2026-01-19"},"month":{"type":"integer","example":1},"day":{"type":"integer","example":19},"day_name":{"type":"string","example":"Monday"},"fajr_start":{"type":"string","example":"06:07"},"fajr_jamaat":{"type":"string","example":"07:00"},"sunrise":{"type":"string","example":"08:13"},"dhuhr_start":{"type":"string","example":"12:22"},"dhuhr_jamaat":{"type":"string","example":"13:00"},"asr_start":{"type":"string","example":"14:37"},"asr_jamaat":{"type":"string","example":"15:00"},"maghrib_start":{"type":"string","example":"16:30"},"maghrib_jamaat":{"type":"string","example":"16:30"},"isha_start":{"type":"string","example":"17:52"},"isha_jamaat":{"type":"string","example":"18:30"},"jummah_time":{"type":["string","null"],"example":"13:00"},"is_ramadan":{"type":"boolean","example":false},"suhoor_end":{"type":["string","null"]},"iftar":{"type":["string","null"]},"hijri_date":{"type":["string","null"]},"hijri_day":{"type":["integer","null"]},"fast_length":{"type":["string","null"]},"taraweeh":{"type":["string","null"]}}},"NewsArticle":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"excerpt":{"type":"string"},"content":{"type":"string","description":"Full HTML content"},"cover_image_url":{"type":["string","null"]},"author_name":{"type":"string"},"category_id":{"type":["string","null"]},"category_name":{"type":["string","null"]},"category_color":{"type":["string","null"]},"status":{"type":"string","enum":["draft","published","archived"]},"is_pinned":{"type":"boolean"},"reading_time_minutes":{"type":"integer"},"published_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Category":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"color":{"type":"string"}}},"Event":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"content":{"type":["string","null"]},"start_datetime":{"type":"string","format":"date-time"},"end_datetime":{"type":"string","format":"date-time"},"timezone":{"type":"string","example":"Europe/London"},"event_type":{"type":"string","enum":["in_person","online","hybrid"]},"category":{"type":"string"},"capacity":{"type":["integer","null"]},"registration_required":{"type":"boolean"},"price":{"type":["number","null"]},"currency":{"type":"string","example":"GBP"},"is_featured":{"type":"boolean"},"status":{"type":"string","enum":["draft","published","cancelled","completed","archived"]}}},"Project":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"goal_amount":{"type":["number","null"]},"raised_amount":{"type":"number"},"currency":{"type":"string","example":"GBP"},"status":{"type":"string"},"is_featured":{"type":"boolean"},"cover_image_url":{"type":["string","null"]}}},"ProjectStats":{"type":"object","properties":{"total_raised":{"type":"number"},"donors_count":{"type":"integer"},"currency":{"type":"string","example":"GBP"}}},"ShopItem":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number"},"currency":{"type":"string","example":"GBP"},"type":{"type":"string","enum":["physical","external","preorder","interest"]},"is_active":{"type":"boolean"},"in_stock":{"type":"boolean"}}},"Location":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"postcode":{"type":"string"},"country":{"type":"string"},"is_active":{"type":"boolean"},"bookings_enabled":{"type":"boolean"},"prayer_times_enabled":{"type":"boolean"}}},"BookableUnit":{"type":"object","properties":{"id":{"type":"string"},"location_id":{"type":"string"},"name":{"type":"string","example":"Main Hall"},"slug":{"type":"string","example":"main-hall"},"type":{"type":"string","enum":["room","hall","outdoor","other"]},"description":{"type":["string","null"]},"hourly_rate":{"type":["number","null"],"example":25},"half_day_rate":{"type":["number","null"],"example":80},"full_day_rate":{"type":["number","null"],"example":150},"min_booking_hours":{"type":"integer","example":1},"max_booking_hours":{"type":"integer","example":12},"requires_approval":{"type":"boolean"},"available_days":{"type":"array","items":{"type":"integer"},"description":"0=Monday, 6=Sunday"},"available_from":{"type":["string","null"],"example":"09:00"},"available_until":{"type":["string","null"],"example":"22:00"},"is_active":{"type":"boolean"}}},"BookingAvailability":{"type":"object","properties":{"unit_id":{"type":"string"},"date":{"type":"string","format":"date"},"slots":{"type":"array","items":{"type":"object","properties":{"start_time":{"type":"string","example":"09:00"},"end_time":{"type":"string","example":"09:30"},"available":{"type":"boolean"}}}}}},"DonationStats":{"type":"object","properties":{"total_raised":{"type":"number"},"donors_count":{"type":"integer"},"currency":{"type":"string","example":"GBP"}}},"Announcement":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string","example":"Jummah Time Change"},"message":{"type":"string","example":"Friday prayers will be at 1:30 PM starting next week."},"link_url":{"type":["string","null"]},"link_text":{"type":["string","null"]},"priority":{"type":"string","enum":["info","warning","urgent"]}}},"WebsiteAnnouncement":{"type":"object","description":"Active website banner announcement (null if none)","properties":{"id":{"type":"string"},"title":{"type":"string"},"body":{"type":"string"},"display_mode":{"type":"string","enum":["banner","sticky","popup","sticky_and_popup"]}}},"SearchResponse":{"type":"object","properties":{"query":{"type":"string"},"results":{"type":"object","description":"Results grouped by category (news, events, projects, etc.)","additionalProperties":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":["string","null"]},"href":{"type":"string"},"category":{"type":"string"}}}},"total":{"type":"integer"}}}},"timing_ms":{"type":"number"}}},"RadioSchedule":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":["string","null"],"format":"date-time"},"timezone":{"type":"string"},"is_active":{"type":"boolean"},"next_execution_at":{"type":["string","null"],"format":"date-time"}}},"RadioSession":{"type":"object","description":"A live radio broadcast session","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string"},"started_at":{"type":["string","null"],"format":"date-time"},"started_by_name":{"type":["string","null"]},"chat_enabled":{"type":"boolean"},"peak_listeners":{"type":"integer"},"total_unique_listeners":{"type":"integer"}}},"RadioRecording":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"duration":{"type":"number","description":"Duration in seconds"},"file_size":{"type":"integer"},"format":{"type":"string"},"play_count":{"type":"integer"},"recording_started_at":{"type":"string","format":"date-time"},"recording_ended_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"LmsClass":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"class_type":{"type":"string"},"delivery_mode":{"type":"string","enum":["in_person","online","hybrid"]},"schedule":{"type":"array","items":{"$ref":"#/components/schemas/WeeklySlot"}},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"},"max_capacity":{"type":["integer","null"]},"current_enrollment_count":{"type":"integer"},"fee_amount":{"type":"integer"},"fee_frequency":{"type":"string"},"category_name":{"type":["string","null"]},"level":{"type":["string","null"]},"location_name":{"type":["string","null"]}}},"LmsClassDetail":{"type":"object","description":"Detailed class view with course modules","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"class_type":{"type":"string"},"delivery_mode":{"type":"string"},"schedule":{"type":"array","items":{"$ref":"#/components/schemas/WeeklySlot"}},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"},"max_capacity":{"type":["integer","null"]},"current_enrollment_count":{"type":"integer"},"fee_amount":{"type":"integer"},"fee_frequency":{"type":"string"},"fee_description":{"type":["string","null"]},"requires_approval":{"type":"boolean"},"gender_restriction":{"type":"string"},"min_age":{"type":["integer","null"]},"max_age":{"type":["integer","null"]},"category_name":{"type":["string","null"]},"level":{"type":["string","null"]},"location_name":{"type":["string","null"]},"course_modules":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":["string","null"]},"order":{"type":"integer"},"lesson_count":{"type":"integer"}}}},"course_total_lessons":{"type":"integer"},"course_learning_outcomes":{"type":"array","items":{"type":"string"}}}},"WeeklySlot":{"type":"object","properties":{"day_of_week":{"type":"integer","description":"0=Monday, 6=Sunday"},"start_time":{"type":"string","example":"10:00"},"end_time":{"type":"string","example":"11:30"}}},"LmsCategory":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"color":{"type":"string"},"icon":{"type":["string","null"]},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}},"CertificateVerification":{"type":"object","properties":{"valid":{"type":"boolean"},"certificate":{"type":["object","null"],"properties":{"title":{"type":"string"},"student_name":{"type":"string"},"class_name":{"type":["string","null"]},"course_name":{"type":["string","null"]},"awarded_at":{"type":"string","format":"date-time"}}}}},"DuaCategory":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"sort_order":{"type":"integer"}}},"Dua":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"arabic_text":{"type":["string","null"]},"transliteration":{"type":["string","null"]},"translation":{"type":["string","null"]},"category_name":{"type":["string","null"]},"source":{"type":["string","null"]},"when_to_read":{"type":["string","null"]},"audio_url":{"type":["string","null"]}}},"HadithCollection":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"hadith_count":{"type":"integer"},"book_count":{"type":"integer"}}},"HadithCollectionDetail":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"hadith_count":{"type":"integer"},"book_count":{"type":"integer"},"books":{"type":"array","items":{"type":"object","properties":{"book_number":{"type":"integer"},"title":{"type":"string"},"hadith_start":{"type":"integer"},"hadith_end":{"type":"integer"}}}}}},"Hadith":{"type":"object","properties":{"id":{"type":"string"},"collection_slug":{"type":"string"},"book_number":{"type":"integer"},"hadith_number":{"type":"integer"},"arabic_text":{"type":"string"},"english_text":{"type":"string"},"grades":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"grade":{"type":"string"}}}}}},"Reading":{"type":"object","description":"Devotional reading (ziyarat, prayer, adhkar)","properties":{"id":{"type":"string"},"title":{"type":"string"},"reading_type":{"type":"string"},"arabic_text":{"type":["string","null"]},"translation":{"type":["string","null"]},"description":{"type":["string","null"]},"suggested_schedule":{"type":["string","null"]},"category":{"type":["string","null"]},"file_url":{"type":["string","null"]}}},"Surah":{"type":"object","properties":{"number":{"type":"integer","example":1},"name_arabic":{"type":"string","example":"الفاتحة"},"name_simple":{"type":"string","example":"Al-Fatihah"},"name_translation":{"type":"string","example":"The Opening"},"revelation_place":{"type":"string","example":"makkah"},"verses_count":{"type":"integer","example":7},"pages":{"type":"array","items":{"type":"integer"}}}},"SurahDetail":{"type":"object","properties":{"surah":{"$ref":"#/components/schemas/Surah"},"ayahs":{"type":"array","items":{"$ref":"#/components/schemas/Ayah"}}}},"Ayah":{"type":"object","properties":{"verse_key":{"type":"string","example":"1:1"},"ayah_number":{"type":"integer"},"juz_number":{"type":"integer"},"page_number":{"type":"integer"},"text_indopak":{"type":"string"},"translation_en":{"type":"string"}}},"MushafPage":{"type":"object","properties":{"page_number":{"type":"integer"},"juz_number":{"type":"integer"},"lines":{"type":"array","items":{"type":"object","properties":{"line_number":{"type":"integer"},"line_type":{"type":"string","enum":["text","surah_header","bismillah"]},"words":{"type":"array","items":{"type":"object","properties":{"position":{"type":"integer"},"text_indopak":{"type":"string"},"char_type":{"type":"string","enum":["word","end"]},"verse_key":{"type":"string"}}}}}}}}},"JuzDetail":{"type":"object","properties":{"juz_number":{"type":"integer"},"surah_groups":{"type":"array","items":{"type":"object","properties":{"surah":{"$ref":"#/components/schemas/Surah"},"ayahs":{"type":"array","items":{"$ref":"#/components/schemas/Ayah"}}}}}}},"Campaign":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":["string","null"]},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active","completed","draft"]},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"},"current_count":{"type":"integer"},"participant_count":{"type":"integer"},"activity_count":{"type":"integer"},"featured":{"type":"boolean"},"image_url":{"type":["string","null"]}}},"CampaignDetail":{"type":"object","properties":{"campaign":{"$ref":"#/components/schemas/Campaign"},"activities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"activity_type":{"type":"string"},"description":{"type":["string","null"]},"arabic_text":{"type":["string","null"]},"transliteration":{"type":["string","null"]},"translation":{"type":["string","null"]},"target_count":{"type":["integer","null"]},"current_count":{"type":"integer"},"participant_count":{"type":"integer"},"progress_pct":{"type":["integer","null"]}}}}}},"CampaignContributors":{"type":"object","properties":{"activities":{"type":"array","items":{"type":"object","properties":{"activity_id":{"type":"string"},"activity_title":{"type":"string"},"contributors":{"type":"array","items":{"type":"object","properties":{"user_name":{"type":"string"},"contribution_count":{"type":"integer"},"is_anonymous":{"type":"boolean"}}}}}}}}},"CampaignBreakdown":{"type":"object","properties":{"campaign_id":{"type":"string"},"period_type":{"type":"string","enum":["day","week","month"]},"activities":{"type":"array","items":{"type":"object","properties":{"activity_id":{"type":"string"},"activity_title":{"type":"string"},"total_all_time":{"type":"integer"},"periods":{"type":"array","items":{"type":"object","properties":{"period_label":{"type":"string"},"total_amount":{"type":"integer"},"contributor_count":{"type":"integer"}}}}}}}}},"CommunityBoard":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"},"board_mode":{"type":"string","enum":["structured","open"]},"category":{"type":"string","enum":["food","donation","help","general"]},"visibility":{"type":"string","enum":["public","members"]},"location":{"type":["string","null"]},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"},"slot_count":{"type":"integer"},"pledge_count":{"type":"integer"}}},"CommunityBoardDetail":{"type":"object","description":"Full board with groups, slots, and pledges","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"},"board_mode":{"type":"string"},"category":{"type":"string"},"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"date":{"type":["string","null"],"format":"date"},"slots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slot_type":{"type":"string","enum":["signup","item","food"]},"quantity_needed":{"type":"integer"},"quantity_filled":{"type":"integer"},"is_full":{"type":"boolean"}}}}}}}}},"VolunteerDrive":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["recurring","one_off","open_ended"]},"schedule":{"type":["string","null"]},"location":{"type":["string","null"]},"capacity":{"type":["integer","null"]},"filled":{"type":"integer"},"requirements":{"type":"array","items":{"type":"string"}},"skills_needed":{"type":"array","items":{"type":"string"}},"requires_dbs":{"type":"boolean"},"start_date":{"type":["string","null"],"format":"date"},"end_date":{"type":["string","null"],"format":"date"}}}}}}