diff --git a/docs/content_apis_versioned/4.0.0/posts-controller-feed.api.mdx b/docs/content_apis_versioned/4.0.0/posts-controller-feed.api.mdx
index 974bb08c..ce94dc18 100644
--- a/docs/content_apis_versioned/4.0.0/posts-controller-feed.api.mdx
+++ b/docs/content_apis_versioned/4.0.0/posts-controller-feed.api.mdx
@@ -36,4 +36,3 @@ Quran Reflect lessons and reflections feed retrieved successfully with paginatio
Most recent visible comment summary when available. Use the dedicated comment endpoints to retrieve full comment objects.
author object required
avatarUrls object required
room object nullable
mentions object[]
Array [
avatarUrls object required
]
Invalid profile data or username taken
diff --git a/openAPI/oauth2-apis/v1.json b/openAPI/oauth2-apis/v1.json
index e28a310b..078999ac 100644
--- a/openAPI/oauth2-apis/v1.json
+++ b/openAPI/oauth2-apis/v1.json
@@ -537,4 +537,3 @@
}
}
}
-
diff --git a/openAPI/user-related-apis/v1.json b/openAPI/user-related-apis/v1.json
index 732d5e36..64442202 100644
--- a/openAPI/user-related-apis/v1.json
+++ b/openAPI/user-related-apis/v1.json
@@ -1 +1,27353 @@
-{"openapi":"3.0.0","info":{"title":"User-related APIs","version":"1.0.0","description":"Quran.Foundation user-related APIs enable your app to seamlessly integrate with Quran.Foundation's user-centric features, providing access to personalized notes, bookmarks, goals, streaks, reading sessions, and more. This differentiates them from [content APIs](/docs/category/content-apis) that focus on non-user-specific resources like translations, tafsirs, and verses.\n\n ## How to get access \n\n We are using OAuth2 flows to authenticate and authorize requests. To get started, you need to [get an access token](/docs/tutorials/oidc/getting-started-with-oauth2#obtaining-oauth-20-client-credentials) to make requests to our APIs. Then follow the steps mentioned [here](/docs/tutorials/oidc/getting-started-with-oauth2). \n\n For web applications, the recommended integration pattern is backend token exchange plus backend or server-side proxy calls to User APIs. Your app can keep the user session in secure server storage or `httpOnly` cookies, while your backend injects `x-auth-token` and `x-client-id` on outbound requests to Quran.Foundation APIs.\n\n ## Pagination \n\n We are using cursor based pagination. The pagination query params consist of `first`,`after`, `before` and `last`. \n\n Example \n - `first: 10` will give you first 10 items \n - `first: 10, after: xyz` will give you first 10 items after the item with id `xyz` \n - `last: 10` will give you the last 10 items \n - `last: 10, before: xyz` will give you the last 10 items before the item with id `xyz` \n\n The only possible combinations are `first + after` or `last + before`. They should not be used together"},"servers":[{"url":"https://apis-prelive.quran.foundation/auth","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/auth","description":"Production Server"}],"components":{"securitySchemes":{"x-auth-token":{"type":"apiKey","in":"header","name":"x-auth-token","description":"The JWT access token required for accessing the endpoints."},"x-client-id":{"type":"apiKey","in":"header","name":"x-client-id","description":"Your client id"}},"schemas":{"NullableBookmark":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wqim00057z3fe30y0b3e"},"createdAt":{"type":"string","format":"date-time","example":"2023-01-21T07:28:13.023Z"},"type":{"type":"string","example":"ayah"},"key":{"type":"integer","example":1},"verseNumber":{"type":"integer","nullable":true,"example":5},"group":{"type":"string","example":"verses_6236"},"isInDefaultCollection":{"type":"boolean","example":true},"isReading":{"type":"boolean","nullable":true,"example":false},"collectionsCount":{"type":"integer","description":"Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.","example":1}},"required":["id","createdAt","type","key","group","isInDefaultCollection","isReading"],"additionalProperties":false,"nullable":true},"RawBookmark":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wqiu00067z3fh6oieeiq"},"createdAt":{"type":"string","format":"date-time","example":"2023-01-21T07:28:13.023Z"},"bookmarkType":{"oneOf":[{"type":"string","example":"ayah"},{"type":"object","properties":{"type":{"type":"string","example":"ayah"}},"required":["type"]}]},"key":{"type":"integer","example":1},"verseNumber":{"type":"integer","nullable":true,"example":5},"bookmarkGroup":{"oneOf":[{"type":"string","example":"verses_6236"},{"type":"object","properties":{"name":{"type":"string","example":"verses_6236"}},"required":["name"]}]},"isInDefaultCollection":{"type":"boolean","example":true},"isReading":{"type":"boolean","nullable":true,"example":false}},"required":["id","createdAt","bookmarkType","key","bookmarkGroup","isInDefaultCollection","isReading"]},"Bookmark":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wqim00057z3fe30y0b3e"},"createdAt":{"type":"string","format":"date-time","example":"2023-01-21T07:28:13.023Z"},"type":{"type":"string","example":"ayah"},"key":{"type":"integer","example":1},"verseNumber":{"type":"integer","nullable":true,"example":5},"group":{"type":"string","example":"verses_6236"},"isInDefaultCollection":{"type":"boolean","example":true},"isReading":{"type":"boolean","nullable":true,"example":false},"collectionsCount":{"type":"integer","description":"Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.","example":1}},"required":["id","createdAt","type","key","group","isInDefaultCollection","isReading"],"additionalProperties":false},"BookmarkWithCollectionsCount":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wqim00057z3fe30y0b3e"},"createdAt":{"type":"string","format":"date-time","example":"2023-01-21T07:28:13.023Z"},"type":{"type":"string","example":"ayah"},"key":{"type":"integer","example":1},"verseNumber":{"type":"integer","nullable":true,"example":5},"group":{"type":"string","example":"verses_6236"},"isInDefaultCollection":{"type":"boolean","example":true},"isReading":{"type":"boolean","nullable":true,"example":false},"collectionsCount":{"type":"integer","description":"Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.","example":1}},"required":["id","createdAt","type","key","group","isInDefaultCollection","isReading","collectionsCount"],"additionalProperties":false},"Collection":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wqsk00087z3f5hp42h08"},"name":{"type":"string","example":"Woman in Quran"},"slug":{"type":"string","nullable":true,"example":"woman-in-quran"},"isPrivate":{"type":"boolean","example":false},"isDefault":{"type":"boolean","example":false},"updatedAt":{"type":"string","format":"date-time","nullable":true,"example":"2023-01-21T07:28:13.023Z"},"url":{"type":"string","nullable":true,"example":"cmnkcpmvc000814v9f5jtbsxf"},"bookmarksCount":{"type":"integer","example":1},"resourcesCount":{"type":"integer","example":1},"count":{"type":"integer","example":1}},"required":["id","name","slug","isPrivate","isDefault","updatedAt"],"additionalProperties":false},"EstimatedGoalTimelineDay":{"type":"object","properties":{"date":{"type":"string","format":"date-time","description":"The date of the estimated day","example":"2023-01-21T07:28:13.023Z"},"amount":{"oneOf":[{"type":"string","example":"1:5-1:10"},{"type":"integer","minimum":1,"example":600}],"description":"The amount of the day's goal."}},"required":["date","amount"],"additionalProperties":false},"EstimatedGoalTimeline":{"type":"object","properties":{"week":{"type":"array","items":{"$ref":"#/components/schemas/EstimatedGoalTimelineDay"}}},"additionalProperties":false},"Preference":{"type":"object","properties":{"theme":{"type":"object","properties":{"type":{"type":"string","enum":["auto","light","sepia","dark"],"example":"auto"}},"additionalProperties":false},"reading":{"type":"object","properties":{"readingPreference":{"type":"string","enum":["translation","reading","readingTranslation"],"example":"translation"},"selectedWordByWordLocale":{"type":"string","enum":["en","ur","id","bn","tr","fa","ru","hi","de","ta","inh","fr","sq","dv","zh","sd","ml"],"example":"en"},"wordClickFunctionality":{"type":"string","enum":["play-audio","no-audio"],"example":"play-audio"},"isReadingByRevelationOrder":{"type":"boolean","example":true},"wordByWordContentType":{"type":"array","items":{"type":"string","enum":["translation","transliteration"]},"example":["translation"]},"wordByWordDisplay":{"type":"array","items":{"type":"string","enum":["tooltip","inline"]},"example":["tooltip"]},"wordByWordTooltipContentType":{"type":"array","items":{"type":"string","enum":["translation","transliteration"]},"example":["translation"]},"wordByWordInlineContentType":{"type":"array","items":{"type":"string","enum":["translation","transliteration"]},"example":[]},"selectedReadingTranslation":{"type":"string","minLength":1,"maxLength":255,"example":"131"},"selectedReflectionLanguages":{"type":"array","items":{"type":"string","maxLength":10},"minItems":1},"selectedLessonLanguages":{"type":"array","items":{"type":"string","maxLength":10},"minItems":1}},"required":["readingPreference","selectedWordByWordLocale","wordClickFunctionality","selectedReadingTranslation"],"additionalProperties":false},"quranReaderStyles":{"type":"object","properties":{"tafsirFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"quranTextFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"translationFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"wordByWordFontScale":{"type":"integer","minimum":1,"maximum":6,"example":3},"reflectionFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"qnaFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"lessonFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"surahInfoFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"hadithFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"layersFontScale":{"type":"integer","minimum":1,"maximum":10,"example":3},"quranFont":{"type":"string","enum":["code_v1","code_v2","text_uthmani","text_indopak","qpc_uthmani_hafs","tajweed","tajweed_v4"],"example":"code_v1"},"mushafLines":{"type":"string","enum":["15_lines","16_lines"],"example":"16_lines"},"showTajweedRules":{"type":"boolean","example":true}},"required":["tafsirFontScale","quranTextFontScale","translationFontScale","wordByWordFontScale","reflectionFontScale","qnaFontScale","lessonFontScale","surahInfoFontScale","hadithFontScale","layersFontScale"],"additionalProperties":false},"translations":{"type":"object","properties":{"selectedTranslations":{"type":"array","items":{"type":"integer","example":131}}},"additionalProperties":false},"tafsirs":{"type":"object","properties":{"selectedTafsirs":{"type":"array","items":{"type":"string","example":"en-tafisr-ibn-kathir"}}},"additionalProperties":false},"audio":{"type":"object","properties":{"reciter":{"type":"integer","example":7},"playbackRate":{"type":"integer","enum":[0.25,0.5,0.75,1,1.25,1.5,1.75,2],"example":1},"showTooltipWhenPlayingAudio":{"type":"boolean","example":true},"enableAutoScrolling":{"type":"boolean","example":true}},"required":["reciter"],"additionalProperties":false},"language":{"type":"object","properties":{"language":{"type":"string","enum":["en","ar","bn","fa","fr","id","it","nl","pt","ru","sq","th","tr","ur","zh","ms","es","sw","vi"]}},"additionalProperties":false},"userHasCustomised":{"type":"object","properties":{"userHasCustomised":{"type":"boolean","example":false}},"required":["userHasCustomised"],"additionalProperties":false}},"additionalProperties":false},"ReadingSession":{"type":"object","properties":{"id":{"type":"string","example":"cmoa3wrpk000h7z3f2t6a57dg"},"updatedAt":{"type":"string","format":"date-time","example":"2023-01-21T07:28:13.023Z"},"chapterNumber":{"type":"integer","example":1},"verseNumber":{"type":"integer","example":5}},"required":["id","updatedAt"],"additionalProperties":false},"UserProfile":{"type":"object","properties":{"id":{"type":"string"},"createdAt":{"type":"string","format":"date-time","example":"2022-12-06T06:16:20.229Z"},"email":{"type":"string","example":"muhajir@quran.com"},"firstName":{"type":"string","example":"Muhammad"},"lastName":{"type":"string","example":"Muhajir"},"photoUrl":{"type":"string","example":"https://photos.quran.com/img/muhajir.jpg"}},"additionalProperties":false},"EditProfileDto":{"type":"object","properties":{"languageId":{"type":"number"},"reflectionLanguages":{"type":"array","items":{"type":"string"}},"ayahLanguages":{"type":"array","items":{"type":"string"}},"customized":{"type":"boolean"},"hideFollowSuggestion":{"type":"boolean","description":"Hide follow suggestion popup after liking a post"},"showFollowFeaturedSuggestion":{"type":"boolean","description":"Show featured follow suggestion popup on QR onboarding"}}},"UserSerializedDto":{"type":"object","properties":{"avatarUrls":{"type":"object","example":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"}},"createdAt":{"type":"object","example":"2000-01-21 00:00:00"},"joiningYear":{"type":"number","example":2025},"isPasswordSet":{"type":"boolean","example":true},"settings":{"type":"object","properties":{"ayahLanguages":{"required":false,"type":"array","items":{"type":"number"}},"reflectionLanguages":{"required":false,"type":"array","items":{"type":"number"}}}},"username":{"type":"string"},"id":{"type":"string"},"verified":{"type":"boolean","default":false},"postAs":{"type":"boolean","default":false},"firstName":{"type":"string"},"lastName":{"type":"string"},"postsCount":{"type":"number","default":0},"averageToxicity":{"type":"number","default":0},"languageId":{"type":"number"},"banned":{"type":"boolean","default":false},"memberType":{"type":"number"},"followersCount":{"type":"number","default":0},"likesCount":{"type":"number","default":0},"isAdmin":{"type":"boolean","default":false},"languageIsoCode":{"type":"string","default":"en"},"bio":{"type":"string"},"country":{"type":"string"},"followed":{"type":"boolean"}},"required":["avatarUrls","createdAt","joiningYear","settings","id"]},"UpdateProfileDto":{"type":"object","properties":{"avatar":{"type":"string","pattern":"/^data:image\\/[a-z]+;base64,/"},"firstName":{"type":"string"},"lastName":{"type":"string"},"bio":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"removeAvatar":{"type":"boolean"}}},"UpdateProfileBodyDto":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/UpdateProfileDto"}},"required":["user"]},"UserRoomDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"group":{"type":"string"},"public":{"type":"boolean"},"roomType":{"type":"string"},"verified":{"type":"boolean"},"subdomain":{"type":"string"},"description":{"type":"string"},"membersCount":{"type":"number"},"avatarUrl":{"type":"object","properties":{"small":{"required":true,"type":"string"},"medium":{"required":true,"type":"string"},"large":{"required":true,"type":"string"}}}},"required":["id","name","group","public","roomType","verified","subdomain","description","membersCount","avatarUrl"]},"UserRoomsResponse":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/UserRoomDto"}}},"required":["total","currentPage","limit","pages","data"]},"UserSearchDto":{"type":"object","properties":{"avatarUrls":{"type":"object","example":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"}},"createdAt":{"type":"object","example":"2000-01-21 00:00:00"},"joiningYear":{"type":"number","example":2025},"isPasswordSet":{"type":"boolean","example":true},"isFollowed":{"type":"boolean","example":false},"followed":{"type":"boolean","example":false},"settings":{"type":"object","properties":{"ayahLanguages":{"required":false,"type":"array","items":{"type":"number"}},"reflectionLanguages":{"required":false,"type":"array","items":{"type":"number"}}}},"username":{"type":"string"},"id":{"type":"string"},"verified":{"type":"boolean","default":false},"postAs":{"type":"boolean","default":false},"firstName":{"type":"string"},"lastName":{"type":"string"},"postsCount":{"type":"number","default":0},"averageToxicity":{"type":"number","default":0},"languageId":{"type":"number"},"banned":{"type":"boolean","default":false},"memberType":{"type":"number"},"followersCount":{"type":"number","default":0},"likesCount":{"type":"number","default":0},"isAdmin":{"type":"boolean","default":false},"languageIsoCode":{"type":"string","default":"en"},"bio":{"type":"string"},"country":{"type":"string"}},"required":["avatarUrls","createdAt","joiningYear","settings","id"]},"UsersSearchResponse":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/UserSearchDto"}}},"required":["total","currentPage","limit","pages","data"]},"ToggleFollowDto":{"type":"object","properties":{"action":{"enum":["follow","unfollow"],"type":"string","description":"The intended action: follow or unfollow","example":"follow"}}},"FeaturedUserDto":{"type":"object","properties":{"id":{"type":"string","example":"1f8d6f3f-2f57-4c3e-b7b5-5f6a9d7f7a55"},"username":{"type":"string","example":"example.user"},"verified":{"type":"boolean","example":true},"firstName":{"type":"string","example":"Example"},"lastName":{"type":"string","example":"User"},"fullName":{"type":"string","example":"Example User"},"avatarUrls":{"type":"object","example":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"}},"followersCount":{"type":"number","example":1200},"bio":{"type":"string","example":"I write reflections on the Quran."}},"required":["id","username","verified","firstName","lastName","fullName","avatarUrls","followersCount"]},"FeaturedUsersResponseDto":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/FeaturedUserDto"}}},"required":["total","currentPage","limit","pages","data"]},"FailedFeaturedFollowItemDto":{"type":"object","properties":{"followeeId":{"type":"string","example":"user-id-123"},"reason":{"type":"string","example":"FOLLOW_FAILED"}},"required":["followeeId","reason"]},"FollowFeaturedUsersResponseDto":{"type":"object","properties":{"requested":{"type":"number","example":9},"followed":{"type":"number","example":7},"skipped":{"type":"number","example":1},"failed":{"type":"number","example":1},"complete":{"type":"boolean","example":true},"failedItems":{"type":"array","items":{"$ref":"#/components/schemas/FailedFeaturedFollowItemDto"}}},"required":["requested","followed","skipped","failed","complete"]},"RoomAdminUpdateDto":{"type":"object","properties":{"roomId":{"type":"number"},"userId":{"type":"string"},"admin":{"type":"boolean"}},"required":["roomId","userId","admin"]},"UpdateGroupDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":50},"removeAvatar":{"type":"boolean"},"avatar":{"type":"string","pattern":"/^data:image\\/[a-z]+;base64,/"},"country":{"type":"string","nullable":true},"public":{"type":"boolean","nullable":true,"default":null}},"required":["id"]},"UpdatePageDto":{"type":"object","properties":{"id":{"type":"number"},"removeAvatar":{"type":"boolean"},"avatar":{"type":"string","pattern":"/^data:image\\/[a-z]+;base64,/"},"public":{"type":"boolean","nullable":true,"default":null},"name":{"type":"string"},"description":{"type":"string"},"organizationWebsite":{"type":"string"},"country":{"type":"string"},"url":{"type":"string"}},"required":["id"]},"MemberSerializedDto":{"type":"object","properties":{"id":{"type":"string","example":"user-1"},"username":{"type":"string","example":"member.username"},"firstName":{"type":"string","example":"Member"},"lastName":{"type":"string","example":"User"},"verified":{"type":"boolean","example":true},"avatarUrls":{"type":"object","example":{"small":"https://avatars.quran.foundation/users/user-1/small.png","medium":"https://avatars.quran.foundation/users/user-1/medium.png","large":"https://avatars.quran.foundation/users/user-1/large.png"}},"isAdmin":{"type":"boolean","example":false},"isOwner":{"type":"boolean","example":false},"isFollowed":{"type":"boolean","example":true},"isActive":{"type":"boolean","example":true},"followersCount":{"type":"number","example":42}},"required":["id","username","firstName","lastName","verified","avatarUrls","isAdmin","isOwner","isFollowed","isActive","followersCount"]},"RoomMembersResponseDto":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/MemberSerializedDto"}}},"required":["total","currentPage","limit","pages","data"]},"InviteUserDto":{"type":"object","properties":{"userIds":{"type":"array","items":{"type":"string"}},"emails":{"type":"array","items":{"type":"string"}}},"required":["userIds","emails"]},"RoomInviteUserResponseDto":{"type":"object","properties":{"invited":{"type":"boolean","example":true},"inviteStatus":{"type":"object","additionalProperties":{"oneOf":[{"type":"boolean"},{"type":"string"}]},"example":{"user-123":true,"user-456":"already_a_member"}}},"required":["invited","inviteStatus"]},"RoomInviteAcceptedResponseDto":{"type":"object","properties":{"accepted":{"type":"boolean","example":true}},"required":["accepted"]},"RoomInviteRejectedResponseDto":{"type":"object","properties":{"rejected":{"type":"boolean","example":true}},"required":["rejected"]},"CreatePageDto":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"jobTitle":{"type":"string"},"contactNumber":{"type":"string"},"organizationName":{"type":"string"},"organizationWebsite":{"type":"string"},"purpose":{"type":"string"},"additionalDetails":{"type":"string"},"country":{"type":"string"},"url":{"type":"string"},"public":{"type":"boolean"}},"required":["name","jobTitle","contactNumber","organizationName","purpose","url"]},"CreateGroupDto":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50},"description":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":50},"public":{"type":"boolean"}},"required":["name","url"]},"RoomListItemDto":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"description":{"type":"string"},"roomType":{"type":"string"},"isActive":{"type":"boolean"},"isVerified":{"type":"boolean"},"isPublic":{"type":"boolean"},"isOwner":{"type":"boolean"},"isAdmin":{"type":"boolean"},"ownerId":{"type":"string"},"postsCount":{"type":"number"},"membersCount":{"type":"number"},"url":{"type":"string"},"avatarUrls":{"type":"object","properties":{"thumb":{"required":true,"type":"string"},"original":{"required":true,"type":"string"}}},"createdAt":{"format":"date-time","type":"string"},"isMember":{"type":"boolean"},"subdomain":{"type":"string"},"country":{"type":"string"}},"required":["id","name","description","roomType","isActive","isVerified","isPublic","isOwner","isAdmin","ownerId","postsCount","membersCount","avatarUrls"]},"RoomCreatedResponseDto":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/RoomListItemDto"}},"required":["success","data"]},"PaginatedRoomsResponseDto":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/RoomListItemDto"}}},"required":["total","currentPage","limit","pages","data"]},"RoomProfileResponseDto":{"type":"object","properties":{"privateToken":{"type":"string","example":"private-room-token"},"mutualFollowers":{"type":"array","items":{"$ref":"#/components/schemas/UserSerializedDto"}},"mutualFollowersCount":{"type":"number","example":2},"id":{"type":"number"},"name":{"type":"string"},"description":{"type":"string"},"roomType":{"type":"string"},"isActive":{"type":"boolean"},"isVerified":{"type":"boolean"},"isPublic":{"type":"boolean"},"isOwner":{"type":"boolean"},"isAdmin":{"type":"boolean"},"ownerId":{"type":"string"},"postsCount":{"type":"number"},"membersCount":{"type":"number"},"url":{"type":"string"},"avatarUrls":{"type":"object","properties":{"thumb":{"required":true,"type":"string"},"original":{"required":true,"type":"string"}}},"createdAt":{"format":"date-time","type":"string"},"isMember":{"type":"boolean"},"subdomain":{"type":"string"},"country":{"type":"string"}},"required":["id","name","description","roomType","isActive","isVerified","isPublic","isOwner","isAdmin","ownerId","postsCount","membersCount","avatarUrls"]},"RoomAcceptByPrivateTokenResponseDto":{"type":"object","properties":{"roomId":{"type":"number","example":42},"success":{"type":"boolean","example":true},"isNewMember":{"type":"boolean","example":true}},"required":["roomId","success","isNewMember"]},"PostTag":{"type":"object","properties":{"language":{"type":"string"},"id":{"type":"number"},"name":{"type":"string"}},"required":["id"]},"PostReference":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":"number"},"to":{"type":"number"},"chapterId":{"type":"number"}},"required":["id"]},"UserAuthor":{"type":"object","properties":{"postsCount":{"type":"number"},"avatarUrls":{"type":"object","properties":{"small":{"required":true,"type":"string"},"medium":{"required":true,"type":"string"},"large":{"required":true,"type":"string"}}},"id":{"type":"string"},"username":{"type":"string"},"verified":{"type":"boolean","default":false},"firstName":{"type":"string"},"lastName":{"type":"string"},"memberType":{"type":"number"}},"required":["avatarUrls","id"]},"PostRecentComment":{"type":"object","properties":{"id":{"type":"number"},"author":{"$ref":"#/components/schemas/UserAuthor"},"body":{"type":"string"},"createdAt":{"format":"date-time","type":"string"}},"required":["id","author","body","createdAt"]},"PostRoom":{"type":"object","properties":{"isAdmin":{"type":"object"},"isOwner":{"type":"object"},"isPublic":{"type":"object"},"id":{"type":"number"},"subdomain":{"type":"string"},"roomType":{"type":"string"},"verified":{"type":"boolean","default":false},"name":{"type":"string"},"_group":{"type":"string"}},"required":["id"]},"UserWithMentionLocations":{"type":"object","properties":{"postsCount":{"type":"number"},"avatarUrls":{"type":"object","properties":{"small":{"required":true,"type":"string"},"medium":{"required":true,"type":"string"},"large":{"required":true,"type":"string"}}},"id":{"type":"string"},"username":{"type":"string"},"verified":{"type":"boolean","default":false},"firstName":{"type":"string"},"lastName":{"type":"string"},"memberType":{"type":"number"},"locations":{"type":"object"},"followersCount":{"type":"number"},"displayName":{"type":"string"}},"required":["avatarUrls","id","locations","followersCount"]},"PostSerialized":{"type":"object","properties":{"tags":{"type":"array","items":{"$ref":"#/components/schemas/PostTag"}},"references":{"type":"array","items":{"$ref":"#/components/schemas/PostReference"}},"author":{"type":"object"},"recentComment":{"$ref":"#/components/schemas/PostRecentComment"},"room":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/PostRoom"}]},"mentions":{"type":"array","items":{"$ref":"#/components/schemas/UserWithMentionLocations"}},"isLiked":{"type":"boolean"},"isByFollowedUser":{"type":"boolean"},"isCommentedOn":{"type":"boolean"},"isSaved":{"type":"boolean"},"id":{"type":"number"},"authorId":{"type":"string"},"body":{"type":"string"},"discussionId":{"type":"number"},"draft":{"type":"boolean","default":false},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"publishedAt":{"format":"date-time","type":"string"},"global":{"type":"boolean"},"toxicityScore":{"type":"number"},"reported":{"type":"boolean","default":false},"views":{"type":"number"},"removed":{"type":"boolean","default":false},"verified":{"type":"boolean","default":false},"roomPostStatus":{"description":"@description 0: OnlyMembers, 1: Publicly, 2: AsRoom","default":0,"enum":[0,1,2],"type":"number"},"hidden":{"type":"boolean","default":false},"commentsCount":{"type":"number","default":0},"likesCount":{"type":"number","default":0},"viewsCount":{"type":"number","default":0},"languageId":{"type":"number"},"languageName":{"type":"string"},"moderationStatus":{"description":"featured = 1, // Like Sticky posts, will be featured for a time period.Shown at top in feed and partner apps\n\npromoted = 2, // High quality content.Shown at top(after featured) in feed and partner apps\n\nnormal = 3, // Default status, available in search, latest and popular tabs.In feed(if you're following the author)\n\nhidden = 4, // Visible only to author or moderators, or via private share link.\n\nprivate_note = 5, // Private notes, only visible to author or via private share link.These are the posts made \"private\" by moderators.\n\nrequested_review = 6, // User requested the review, treat them has hidden.Only visible to author and moderators\n\ndeleted = 30,","enum":[1,2,3,4,5,6,30],"type":"number"},"reviewedAt":{"format":"date-time","type":"string"},"featuredAt":{"format":"date-time","type":"string"},"estimatedReadingTime":{"type":"number","default":0},"roomId":{"type":"number"},"postTypeId":{"type":"number"},"postTypeName":{"type":"string"}},"required":["id","authorId","createdAt","updatedAt","commentsCount","roomId","postTypeId"]},"FeedResponseDto":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"data":{"type":"array","items":{"$ref":"#/components/schemas/PostSerialized"}}},"required":["total","currentPage","limit","pages","data"]},"RoomPostUpdatePrivacyDto":{"type":"object","properties":{"isPublic":{"type":"boolean"}},"required":["isPublic"]},"ReferenceAttributes":{"type":"object","properties":{"chapterId":{"type":"number","minimum":1},"from":{"type":"number","default":0},"to":{"type":"number","default":0}},"required":["chapterId","from","to"]},"UserMentionAttributes":{"type":"object","properties":{"marker":{"type":"string","pattern":"/{{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}}/","example":"{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}"},"userId":{"type":"string"},"displayName":{"type":"string"}},"required":["marker","userId","displayName"]},"CreatePostDto":{"type":"object","properties":{"roomPostStatus":{"enum":[0,1,2],"type":"number","description":"The room post status, defaults to publicly: 1. As Room: 0, Publicly: 1, Only Members: 2"},"body":{"type":"string","minLength":6},"draft":{"type":"boolean"},"references":{"type":"array","items":{"$ref":"#/components/schemas/ReferenceAttributes"}},"mentions":{"type":"array","items":{"$ref":"#/components/schemas/UserMentionAttributes"}},"roomId":{"type":"number"},"postAsAuthorId":{"type":"string"},"publishedAt":{"format":"date-time","type":"string"}},"required":["roomPostStatus","body","draft","references","mentions","roomId","postAsAuthorId","publishedAt"]},"CreatePostBodyDto":{"type":"object","properties":{"post":{"$ref":"#/components/schemas/CreatePostDto"}},"required":["post"]},"PostCreatedResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/PostSerialized"},"success":{"type":"boolean"}},"required":["data","success"]},"UpdatePostDto":{"type":"object","properties":{"roomPostStatus":{"enum":[0,1,2],"type":"number","description":"The room post status, defaults to publicly: 1. As Room: 0, Publicly: 1, Only Members: 2"},"body":{"type":"string","minLength":6},"draft":{"type":"boolean"},"references":{"type":"array","items":{"$ref":"#/components/schemas/ReferenceAttributes"}},"mentions":{"type":"array","items":{"$ref":"#/components/schemas/UserMentionAttributes"}},"roomId":{"type":"number"},"postAsAuthorId":{"type":"string"},"publishedAt":{"format":"date-time","type":"string"}}},"ReportAbuseDto":{"type":"object","properties":{"abuse":{"type":"string"},"comments":{"type":"string","default":""}},"required":["abuse","comments"]},"ReportAbuseBodyDto":{"type":"object","properties":{"report":{"$ref":"#/components/schemas/ReportAbuseDto"}},"required":["report"]},"CommentAuthor":{"type":"object","properties":{"postsCount":{"type":"number"},"avatarUrls":{"type":"object","properties":{"small":{"required":true,"type":"string"},"medium":{"required":true,"type":"string"},"large":{"required":true,"type":"string"}}},"id":{"type":"string"},"username":{"type":"string"},"verified":{"type":"boolean","default":false},"firstName":{"type":"string"},"lastName":{"type":"string"},"memberType":{"type":"number"}},"required":["avatarUrls","id"]},"CommentTag":{"type":"object","properties":{"language":{"type":"string"},"id":{"type":"number"},"name":{"type":"string"},"commentsCount":{"type":"number"}},"required":["id"]},"Comment":{"type":"object","properties":{"id":{"type":"number"},"postId":{"type":"number"},"authorId":{"type":"string"},"parentId":{"type":"number"},"isPrivate":{"type":"boolean","default":false},"body":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"toxicityScore":{"type":"number"},"repliesCount":{"type":"number","default":0},"likesCount":{"type":"number","default":0},"reported":{"type":"boolean","default":false},"removed":{"type":"boolean","default":false},"hidden":{"type":"boolean","default":false},"languageId":{"type":"number"},"languageName":{"type":"string"},"moderationStatus":{"type":"number"},"author":{"$ref":"#/components/schemas/CommentAuthor"},"mentions":{"type":"array","items":{"$ref":"#/components/schemas/UserWithMentionLocations"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/CommentTag"}}},"required":["id","postId","authorId","parentId","isPrivate","body","createdAt","updatedAt"]},"PostCommentsResponse":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}},"required":["total","currentPage","limit","pages","comments"]},"PostAllCommentsResponse":{"type":"object","properties":{"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"total":{"type":"number","example":"10 // works also with swagger setup"}},"required":["comments","total"]},"ExportPostsDto":{"type":"object","properties":{"ids":{"description":"Array of post IDs to export","example":[1,2,3],"minItems":1,"type":"array","items":{"type":"number"}}},"required":["ids"]},"Tag":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"updatedAt":{"format":"date-time","type":"string"},"rank":{"type":"number","default":0},"languageId":{"type":"number"},"languageName":{"type":"string"},"postsCount":{"type":"number"},"commentsCount":{"type":"number"}},"required":["id","createdAt","updatedAt"]},"CreateCommentDto":{"type":"object","properties":{"body":{"type":"string","description":"Comment body text","example":"This is a thoughtful comment about the post","maxLength":8000},"postId":{"type":"number","description":"ID of the post this comment belongs to","example":123},"isPrivate":{"type":"boolean","default":false,"description":"Whether the comment is private","example":false},"parentId":{"type":"number","description":"ID of the parent comment (for replies)","example":456},"mentions":{"description":"User mentions in the comment","type":"array","items":{"$ref":"#/components/schemas/UserMentionAttributes"}}},"required":["body","postId","isPrivate"]},"CreateCommentBody":{"type":"object","properties":{"comment":{"description":"Comment details for creation","allOf":[{"$ref":"#/components/schemas/CreateCommentDto"}]}},"required":["comment"]},"CreateCommentResponse":{"type":"object","properties":{"comment":{"$ref":"#/components/schemas/Comment"},"success":{"type":"boolean"}},"required":["comment","success"]},"CommentRepliesResponse":{"type":"object","properties":{"total":{"type":"number","example":10},"currentPage":{"type":"number","example":1},"limit":{"type":"number","example":10},"pages":{"type":"number","example":1},"replies":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}},"comment":{"$ref":"#/components/schemas/Comment"}},"required":["total","currentPage","limit","pages","replies","comment"]}},"responses":{}},"security":[{"x-auth-token":[],"x-client-id":[]}],"paths":{"/v1/collections":{"post":{"description":"Create a new collection under user's account.","tags":["Collections"],"summary":"Add collection","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The name of the new collection to be created.","example":"Woman in Quran"}},"required":["name"],"additionalProperties":false},"example":{"name":"Woman in Quran"}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Collection"}},"additionalProperties":false},"example":{"success":true,"data":{"id":"cmoa3wqsk00087z3f5hp42h08","name":"Woman in Quran","slug":"woman-in-quran","isPrivate":false,"isDefault":false,"updatedAt":"2023-01-21T07:28:13.023Z","url":"cmnkcpmvc000814v9f5jtbsxf","bookmarksCount":1,"resourcesCount":1,"count":1}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1Collections"},"get":{"tags":["Collections"],"description":"List collections owned by the user. This api contains pagination. Read more about [pagination](/docs/user_related_apis_versioned/user-related-apis#pagination)","summary":"Get all collections","parameters":[{"in":"query","name":"sortBy","schema":{"type":"string","enum":["recentlyUpdated","alphabetical"],"description":"Sort the collections list either by the time they were updated at descendingly or alphabetically.","example":"recentlyUpdated"},"description":"Sort the collections list either by the time they were updated at descendingly or alphabetically."},{"in":"query","name":"type","schema":{"type":"string","enum":["page","juz","surah","ayah"],"description":"The bookmark type.","default":"ayah"},"description":"The bookmark type."},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Collection"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wqsk00087z3f5hp42h08","name":"Woman in Quran","slug":"woman-in-quran","isPrivate":false,"isDefault":false,"updatedAt":"2023-01-21T07:28:13.023Z","url":"cmnkcpmvc000814v9f5jtbsxf","bookmarksCount":1,"resourcesCount":1,"count":1}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1Collections"}},"/v1/collections/{collectionId}/bookmarks":{"post":{"description":"Add a bookmark to a collection. Use `collectionId=\"__default__\"` to add an ayah bookmark to the virtual Favorites collection used by Quran.com.","tags":["Collections"],"summary":"Add collection Bookmark","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"The collection ID. Use `__default__` to add an ayah bookmark to the virtual Favorites collection used by Quran.com.","example":"cmoa3wqvw00097z3f9tk87gga"},"required":true,"description":"The collection ID. Use `__default__` to add an ayah bookmark to the virtual Favorites collection used by Quran.com."}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"key":{"type":"integer","description":"The Surah number.","example":2},"type":{"type":"string","enum":["ayah"],"description":"The bookmark type.","default":"ayah"},"verseNumber":{"type":"integer","example":3},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key","verseNumber"],"additionalProperties":false,"title":"Ayah"},{"type":"object","properties":{"key":{"type":"integer","description":"Surah, Juz or page number."},"type":{"type":"string","enum":["juz","page","surah"],"description":"The bookmark type.","example":"surah"},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key"],"additionalProperties":false,"title":"Surah, Juz, Or Page"}]},"example":{"key":2,"type":"ayah","verseNumber":3,"mushafId":4,"mushaf":4}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["collection bookmark added"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"collection bookmark added"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1CollectionsByCollectionIdBookmarks"},"delete":{"description":"Delete a bookmark from a collection by bookmark details. Use `collectionId=\"__default__\"` to remove a bookmark from the virtual Favorites collection. When successfully deleted, the bookmark itself is only detached from the collection unless it becomes an orphan.","tags":["Collections"],"summary":"Delete collection bookmark by details","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection.","example":"cmoa3wr2h000f7z3ffr5fc0z1"},"required":true,"description":"The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object"}},"additionalProperties":false},"example":{"success":true,"data":{}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"key":{"type":"integer","description":"Surah number","example":2},"type":{"type":"string","enum":["ayah"],"description":"The bookmark type.","default":"ayah"},"verseNumber":{"type":"integer","example":3},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key","verseNumber"],"additionalProperties":false,"title":"Ayah"},{"type":"object","properties":{"key":{"type":"integer","description":"Surah, Juz or page number."},"type":{"type":"string","enum":["juz","page","surah"],"description":"The bookmark type.","example":"surah"},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key"],"additionalProperties":false,"title":"Surah, Juz, Or Page"},{"type":"object","properties":{"bookmarkId":{"type":"string","description":"The Id of the bookmark to be deleted.","example":"cmoa3wr2h000e7z3fcxefa6rx"}},"required":["bookmarkId"],"additionalProperties":false,"title":"Bookmark ID"}],"title":"input"},"example":{"key":2,"type":"ayah","verseNumber":3,"mushafId":4,"mushaf":4}}}},"operationId":"authDeleteV1CollectionsByCollectionIdBookmarks"}},"/v1/collections/{collectionId}":{"delete":{"description":"Delete a an existing collection.","tags":["Collections"],"summary":"Delete collection","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"The Id of the collection to be deleted.","example":"cmoa3wqwh000a7z3f0d6y5mte"},"required":true,"description":"The Id of the collection to be deleted."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["collection deleted"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"collection deleted"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authDeleteV1CollectionsByCollectionId"},"get":{"description":"Get all resources that belong to an existing collection by collection id. Use `__default__` to fetch the virtual Favorites collection.","tags":["Collections"],"summary":"Get collection items by id","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"Collection ID. Use `__default__` for the virtual Favorites collection.","example":"cmoa3wr17000d7z3f7ssph68y"},"description":"Collection ID. Use `__default__` for the virtual Favorites collection."},{"in":"query","name":"sortBy","schema":{"type":"string","enum":["recentlyAdded","verseKey"],"description":"Sort the collection items either by the time they were added at descendingly or by Ayah key."},"description":"Sort the collection items either by the time they were added at descendingly or by Ayah key."},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"collection":{"$ref":"#/components/schemas/Collection"},"bookmarks":{"type":"array","items":{"$ref":"#/components/schemas/BookmarkWithCollectionsCount"}}},"additionalProperties":false},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"collection":{"id":"cmoa3wqsk00087z3f5hp42h08","name":"Woman in Quran","slug":"woman-in-quran","isPrivate":false,"isDefault":false,"updatedAt":"2023-01-21T07:28:13.023Z","url":"cmnkcpmvc000814v9f5jtbsxf","bookmarksCount":1,"resourcesCount":1,"count":1},"bookmarks":[{"id":"cmoa3wqim00057z3fe30y0b3e","createdAt":"2023-01-21T07:28:13.023Z","type":"ayah","key":1,"verseNumber":5,"group":"verses_6236","isInDefaultCollection":true,"isReading":false,"collectionsCount":1}]},"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1CollectionsByCollectionId"},"post":{"description":"Update an existing collection.","tags":["Collections"],"summary":"Update collection","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"The Id of the collection to be updated."},"required":true,"description":"The Id of the collection to be updated."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The new name of the collection to be updated."}},"required":["name"],"additionalProperties":false},"example":{"name":"string"}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["collection renamed"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"collection renamed"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1CollectionsByCollectionId"}},"/v1/collections/{collectionId}/bookmarks/{bookmarkId}":{"delete":{"description":"Delete a bookmark from a collection by bookmark ID. Use `collectionId=\"__default__\"` to remove a bookmark from the virtual Favorites collection. When successfully deleted, the bookmark itself is only detached from the collection unless it becomes an orphan.","tags":["Collections"],"summary":"Delete collection bookmark by id","parameters":[{"in":"path","name":"collectionId","schema":{"type":"string","description":"The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection.","example":"cmoa3wqxe000b7z3f6d6ia4ih"},"required":true,"description":"The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection."},{"in":"path","name":"bookmarkId","schema":{"type":"string","description":"The Id of the bookmark to be deleted.","example":"cmoa3wqxe000c7z3f61siesdm"},"required":true,"description":"The Id of the bookmark to be deleted."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["collection bookmark deleted"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"collection bookmark deleted"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authDeleteV1CollectionsByCollectionIdBookmarksByBookmarkId"}},"/v1/collections/all":{"get":{"description":"Get all existing collections along with resources that belong to them.","tags":["Collections"],"summary":"Get all collection items","parameters":[{"in":"query","name":"sortBy","schema":{"type":"string","enum":["recentlyAdded","verseKey"],"description":"Sort the collection items either by the time they were added at descendingly or alphabetically."},"description":"Sort the collection items either by the time they were added at descendingly or alphabetically."},{"in":"query","name":"type","schema":{"type":"string","enum":["page","juz","surah","ayah"],"description":"The bookmark type.","default":"ayah"},"description":"The bookmark type."},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/Bookmark"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wqim00057z3fe30y0b3e","createdAt":"2023-01-21T07:28:13.023Z","type":"ayah","key":1,"verseNumber":5,"group":"verses_6236","isInDefaultCollection":true,"isReading":false,"collectionsCount":1}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1CollectionsAll"}},"/v1/bookmarks":{"post":{"description":"Add or update a bookmark by details. Omit `isReading` to create or update a regular standalone bookmark. Set `isReading=true` to set the user's singleton reading bookmark. Set `isReading=false` to unset the current reading bookmark; in that case the response `data` can be `null` if no reading bookmark was set. For Quran.com-style saved or favorite ayah bookmarks, use `POST /v1/collections/__default__/bookmarks`.","tags":["Bookmarks"],"summary":"Add user bookmark","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"key":{"type":"integer","description":"The Surah number.","example":2},"type":{"type":"string","enum":["ayah"],"description":"The bookmark type.","default":"ayah"},"verseNumber":{"type":"integer","description":"The Ayah number to be added.","example":3},"isReading":{"type":"boolean","description":"Reading bookmark flag. Set `true` to set the user's current reading bookmark. Set `false` to unset the current reading bookmark. Omit this field to create or update a regular bookmark."},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key","type","verseNumber"],"additionalProperties":false,"title":"Ayah"},{"type":"object","properties":{"key":{"type":"integer","description":"Surah, Juz or page number."},"type":{"type":"string","enum":["juz","page","surah"],"description":"The bookmark type.","example":"surah"},"isReading":{"type":"boolean","description":"Reading bookmark flag. Set `true` to set the user's current reading bookmark. Set `false` to unset the current reading bookmark. Omit this field to create or update a regular bookmark."},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"mushaf":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4}},"required":["key","type"],"additionalProperties":false,"title":"Surah, Juz, Or page"}]},"example":{"key":2,"type":"ayah","verseNumber":3,"isReading":true,"mushafId":4,"mushaf":4}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/NullableBookmark"}},"additionalProperties":false},"example":{"success":true,"data":{"id":"cmoa3wqim00057z3fe30y0b3e","createdAt":"2023-01-21T07:28:13.023Z","type":"ayah","key":1,"verseNumber":5,"group":"verses_6236","isInDefaultCollection":true,"isReading":false,"collectionsCount":1}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1Bookmarks"},"get":{"description":"Get all bookmarks. This includes bookmarks belonging to a collection.","tags":["Bookmarks"],"summary":"Get user bookmarks","parameters":[{"in":"query","name":"type","schema":{"type":"string","enum":["page","juz","surah","ayah"],"description":"The bookmark type.","default":"ayah"},"required":false,"description":"The bookmark type."},{"in":"query","name":"isReading","schema":{"type":"boolean","description":"Whether to fetch only the reading bookmark"},"required":false,"description":"Whether to fetch only the reading bookmark"},{"in":"query","name":"key","schema":{"type":"integer","description":"Filter by key (surah/juz/page number)"},"required":false,"description":"Filter by key (surah/juz/page number)"},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"required":false,"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"required":false,"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"required":false,"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"required":false,"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/BookmarkWithCollectionsCount"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wqim00057z3fe30y0b3e","createdAt":"2023-01-21T07:28:13.023Z","type":"ayah","key":1,"verseNumber":5,"group":"verses_6236","isInDefaultCollection":true,"isReading":false,"collectionsCount":1}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1Bookmarks"}},"/v1/bookmarks/{bookmarkId}":{"delete":{"description":"Delete a standalone bookmark by id. This endpoint fully removes orphan bookmarks only. If the bookmark belongs to the virtual Favorites collection or any custom collection, it is not removed; this endpoint only sets `isReading` to `false` and leaves the bookmark attached to those collections. To remove it from Favorites or a custom collection, use the corresponding collection delete endpoint instead.","tags":["Bookmarks"],"summary":"Delete Bookmark","parameters":[{"in":"path","name":"bookmarkId","schema":{"type":"string","description":"The id of the bookmark to be deleted.","example":"cmoa3wqk500077z3f018r4rzn"},"required":true,"description":"The id of the bookmark to be deleted."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["bookmark deleted"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"bookmark deleted"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authDeleteV1BookmarksByBookmarkId"}},"/v1/bookmarks/ayahs-range":{"get":{"description":"Get all bookmarks within a specific Ayahs range.","tags":["Bookmarks"],"summary":"Get bookmarks within a range of Ayahs","parameters":[{"in":"query","name":"chapterNumber","schema":{"type":"integer","description":"The number of the Surah that the Ayahs range belong to."},"required":true,"description":"The number of the Surah that the Ayahs range belong to."},{"in":"query","name":"rangeStartAyahNumber","schema":{"type":"integer","description":"The Ayah number at which the range starts."},"required":true,"description":"The Ayah number at which the range starts."},{"in":"query","name":"rangeEndAyahNumber","schema":{"type":"integer","description":"The Ayah number at which the range ends."},"required":true,"description":"The Ayah number at which the range ends."},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/RawBookmark"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wqiu00067z3fh6oieeiq","createdAt":"2023-01-21T07:28:13.023Z","bookmarkType":"ayah","key":1,"verseNumber":5,"bookmarkGroup":"verses_6236","isInDefaultCollection":true,"isReading":false}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1BookmarksAyahsRange"}},"/v1/bookmarks/bookmark":{"get":{"description":"Get a bookmark by details","tags":["Bookmarks"],"summary":"Get bookmark","parameters":[{"in":"query","name":"verseNumber","schema":{"type":"integer","description":"The Ayah number of the bookmark"},"description":"The Ayah number of the bookmark"},{"in":"query","name":"isReading","schema":{"type":"boolean","description":"Whether to fetch the reading bookmark"},"description":"Whether to fetch the reading bookmark"},{"in":"query","name":"key","schema":{"type":"integer","oneOf":[{},{"x-required":true}],"description":"Surah, Juz or page number.","example":2},"description":"Surah, Juz or page number."},{"in":"query","name":"type","schema":{"type":"string","enum":["page","juz","surah","ayah"],"oneOf":[{},{"x-required":true}],"description":"The bookmark type.","default":"ayah"},"description":"The bookmark type."},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.","example":4},"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name."},{"in":"query","name":"mushaf","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.","example":4},"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Bookmark"}},"additionalProperties":false},"example":{"success":true,"data":{"id":"cmoa3wqim00057z3fe30y0b3e","createdAt":"2023-01-21T07:28:13.023Z","type":"ayah","key":1,"verseNumber":5,"group":"verses_6236","isInDefaultCollection":true,"isReading":false,"collectionsCount":1}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1BookmarksBookmark"}},"/v1/bookmarks/collections":{"get":{"description":"Get named collection IDs for a bookmark by bookmark details. Pass `includeDefault=true` to also append `__default__` when the bookmark belongs to Favorites.","tags":["Bookmarks"],"summary":"Get bookmark collections","parameters":[{"in":"query","name":"key","schema":{"type":"number","format":"float","description":"Surah, Juz or page number."},"required":true,"description":"Surah, Juz or page number."},{"in":"query","name":"type","schema":{"type":"string","enum":["page","juz","surah","ayah"],"description":"The bookmark type.","default":"ayah"},"required":false,"description":"The bookmark type."},{"in":"query","name":"includeDefault","schema":{"type":"boolean","description":"When `true`, append `__default__` if the bookmark belongs to the virtual Favorites collection."},"required":false,"description":"When `true`, append `__default__` if the bookmark belongs to the virtual Favorites collection."},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"required":false,"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"required":false,"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"required":false,"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"required":false,"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"string","description":"Collection ID. When `includeDefault=true`, this array may also include `__default__`.","example":"cmnkcpmvc000814v9f5jtbsxf"}}},"additionalProperties":false},"example":{"success":true,"data":["cmnkcpmvc000814v9f5jtbsxf"]}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1BookmarksCollections"}},"/v1/preferences":{"post":{"description":"Add or update one user preferences group like favorite Tafsirs or translations.","tags":["Preferences"],"summary":"Add or update preference","parameters":[{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"group":{"type":"string","enum":["tafsirs","translations","audio","theme","quranReaderStyles","reading","language","userHasCustomised"],"description":"The preference group to be added or updated.","example":"tafsirs"},"key":{"type":"string","description":"The preference key to be added or updated.","example":"selectedTafsirs"},"value":{"description":"The preference value to be added or updated.","example":"[\"en-tafisr-ibn-kathir\"]"}},"required":["group","key","value"],"additionalProperties":false,"oneOf":[{"type":"object","properties":{"key":{"type":"string","enum":["type"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["readingPreference","selectedWordByWordLocale","wordClickFunctionality","isReadingByRevelationOrder","wordByWordContentType","wordByWordDisplay","wordByWordTooltipContentType","wordByWordInlineContentType","selectedReadingTranslation","selectedReflectionLanguages","selectedLessonLanguages"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["tafsirFontScale","quranTextFontScale","translationFontScale","wordByWordFontScale","reflectionFontScale","qnaFontScale","lessonFontScale","surahInfoFontScale","hadithFontScale","layersFontScale","quranFont","mushafLines","showTajweedRules"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["selectedTranslations"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["selectedTafsirs"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["reciter","playbackRate","showTooltipWhenPlayingAudio","enableAutoScrolling","repeatSettings"]}},"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["language"]}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["en","ar","bn","fa","fr","id","it","nl","pt","ru","sq","th","tr","ur","zh","ms","es","sw","vi"]}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["auto","light","sepia","dark"],"example":"auto"}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["translation","reading","readingTranslation"],"example":"translation"}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["en","ur","id","bn","tr","fa","ru","hi","de","ta","inh","fr","sq","dv","zh","sd","ml"],"example":"en"}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["play-audio","no-audio"],"example":"play-audio"}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"boolean","example":true}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","enum":["translation","transliteration"]},"example":["translation"]}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","enum":["tooltip","inline"]},"example":["tooltip"]}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","enum":["translation","transliteration"]},"example":[]}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["code_v1","code_v2","text_uthmani","text_indopak","qpc_uthmani_hafs","tajweed","tajweed_v4"],"example":"code_v1"}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","enum":["15_lines","16_lines"],"example":"16_lines"}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"integer","minimum":1,"maximum":10,"example":3}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"integer","minimum":1,"maximum":6,"example":3}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"integer","example":131}}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","example":"en-tafisr-ibn-kathir"}}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"integer","enum":[0.25,0.5,0.75,1,1.25,1.5,1.75,2],"example":1}},"additionalProperties":false},{"type":"object","properties":{"value":{"type":"boolean","example":false}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"key":{"type":"string","enum":["userHasCustomised"]}},"required":["key"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"string","minLength":1,"maxLength":255,"example":"131"}},"required":["value"],"additionalProperties":false},{"type":"object","properties":{"value":{"type":"array","items":{"type":"string","maxLength":10},"minItems":1}},"required":["value"],"additionalProperties":false}]},"example":{"key":"type"}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["preference updated"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"preference updated"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1Preferences"},"get":{"description":"Get all user preferences like theme, favorite reciter, default language etc.","tags":["Preferences"],"summary":"Get user preferences","parameters":[],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/Preference"}},"additionalProperties":false},"example":{"success":true,"data":{"theme":{"type":"auto"},"reading":{"readingPreference":"translation","selectedWordByWordLocale":"en","wordClickFunctionality":"play-audio","isReadingByRevelationOrder":true,"wordByWordContentType":["translation"],"wordByWordDisplay":["tooltip"],"wordByWordTooltipContentType":["translation"],"wordByWordInlineContentType":[],"selectedReadingTranslation":"131","selectedReflectionLanguages":["string"],"selectedLessonLanguages":["string"]},"quranReaderStyles":{"tafsirFontScale":3,"quranTextFontScale":3,"translationFontScale":3,"wordByWordFontScale":3,"reflectionFontScale":3,"qnaFontScale":3,"lessonFontScale":3,"surahInfoFontScale":3,"hadithFontScale":3,"layersFontScale":3,"quranFont":"code_v1","mushafLines":"16_lines","showTajweedRules":true},"translations":{"selectedTranslations":[131]},"tafsirs":{"selectedTafsirs":["en-tafisr-ibn-kathir"]},"audio":{"reciter":7,"playbackRate":1,"showTooltipWhenPlayingAudio":true,"enableAutoScrolling":true},"language":{"language":"en"},"userHasCustomised":{"userHasCustomised":false}}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1Preferences"}},"/v1/preferences/bulk":{"post":{"description":"Add or update one or more user preferences groups like favorite Tafsirs and translations.","tags":["Preferences"],"summary":"Bulk add or update preferences","parameters":[{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Preference"},"example":{"theme":{"type":"auto"},"reading":{"readingPreference":"translation","selectedWordByWordLocale":"en","wordClickFunctionality":"play-audio","isReadingByRevelationOrder":true,"wordByWordContentType":["translation"],"wordByWordDisplay":["tooltip"],"wordByWordTooltipContentType":["translation"],"wordByWordInlineContentType":[],"selectedReadingTranslation":"131","selectedReflectionLanguages":["string"],"selectedLessonLanguages":["string"]},"quranReaderStyles":{"tafsirFontScale":3,"quranTextFontScale":3,"translationFontScale":3,"wordByWordFontScale":3,"reflectionFontScale":3,"qnaFontScale":3,"lessonFontScale":3,"surahInfoFontScale":3,"hadithFontScale":3,"layersFontScale":3,"quranFont":"code_v1","mushafLines":"16_lines","showTajweedRules":true},"translations":{"selectedTranslations":[131]},"tafsirs":{"selectedTafsirs":["en-tafisr-ibn-kathir"]},"audio":{"reciter":7,"playbackRate":1,"showTooltipWhenPlayingAudio":true,"enableAutoScrolling":true},"language":{"language":"en"},"userHasCustomised":{"userHasCustomised":false}}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["preferences updated"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"preferences updated"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1PreferencesBulk"}},"/v1/reading-sessions":{"post":{"description":"Track the user's most recent reading location (Surah/Ayah) for \"Continue reading\" / \"Recently read\" UX.\n\nA new reading session will be created if the user does not have an existing one in the past 20 minutes; otherwise, the existing reading session will be updated with the latest read Ayah.\n\nFor streaks, goals, and calendar-style progress tracking, see [Reading Sessions vs Activity Days](/docs/user-related-apis/reading-sessions-vs-activity-days).","tags":["Reading Sessions"],"summary":"Add or update user reading session","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"chapterNumber":{"type":"integer","minimum":1,"description":"The Surah number to be added to reading session.","example":1},"verseNumber":{"type":"integer","minimum":1,"description":"The Ayah number to be added to reading session.","example":1}},"required":["chapterNumber","verseNumber"],"additionalProperties":false},"example":{"chapterNumber":1,"verseNumber":1}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"type":"string","enum":["reading session created","reading session updated"],"example":"reading session created"}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"reading session created"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1ReadingSessions"},"get":{"description":"Get the user's reading sessions (most recent first). Reading sessions track recent Surah/Ayah locations for \"Continue reading\" / \"Recently read\". For streaks, goals, and calendar-style progress tracking, use Activity Days.","tags":["Reading Sessions"],"summary":"Get user reading sessions","parameters":[{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ReadingSession"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wrpk000h7z3f2t6a57dg","updatedAt":"2023-01-21T07:28:13.023Z","chapterNumber":1,"verseNumber":5}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1ReadingSessions"}},"/v1/goals/get-todays-plan":{"get":{"description":"Get today's goal plan.","tags":["Goals"],"summary":"Get today's goal plan","parameters":[{"in":"query","name":"type","schema":{"type":"string","enum":["QURAN_TIME","QURAN_PAGES","QURAN_RANGE","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The type of the goal.","example":"QURAN_TIME"},"required":true,"description":"The type of the goal."},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"hasGoal":{"type":"boolean","description":"User has a goal.","example":false}},"required":["hasGoal"],"additionalProperties":false,"oneOf":[{"type":"object","properties":{"id":{"type":"string","description":"The id of the activity day.","example":"cmoa3wq2b00047z3fbl4c6ew0"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date of the activity day.","example":"2023-09-31"},"progress":{"type":"number","format":"float","minimum":0,"maximum":1,"description":"The progress of the reading goal of that activity day (if the user has a reading goal on that day).","example":0.695},"type":{"type":"string","enum":["QURAN","LESSON","QURAN_READING_PROGRAM"],"description":"The type of the activity day","example":"QURAN"},"ranges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The ranges read on that day (will be included only when the type is QURAN)","example":["1:1-1:2"]},"pagesRead":{"oneOf":[{"type":"number","format":"float"}],"description":"The number of pages read on that day (will be included only when the type is QURAN)","example":1.637041020126048},"secondsRead":{"oneOf":[{"type":"integer"}],"description":"The number of seconds spent reading on that day (will be included only when the type is QURAN)","example":417},"versesRead":{"oneOf":[{"type":"integer"}],"description":"The number of Ayahs read on that day (will be included only when the type is QURAN)","example":24},"manuallyAddedSeconds":{"oneOf":[{"type":"integer"}],"description":"The number of seconds spent reading that was manually input by the user and not auto-tracked (will be included only when the type is QURAN)","example":24},"dailyTargetPages":{"oneOf":[{"type":"number","format":"float"}],"description":"The number of pages user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":1.637041020126048},"dailyTargetSeconds":{"oneOf":[{"type":"integer"}],"description":"The number of seconds user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":5},"dailyTargetRanges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":["1:1-1:2"]},"remainingDailyTargetRanges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The remaining range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":["1:1-1:2"]},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4}},"required":["id","date","progress","type","mushafId"],"additionalProperties":false,"description":"The Mushaf used to read on that day (will be included only when the type is QURAN) \n\nThe id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","title":"When user has a goal"}]}},"additionalProperties":false},"example":{"success":true,"data":{"id":"cmoa3wq2b00047z3fbl4c6ew0","date":"2023-09-31","progress":0.695,"type":"QURAN","ranges":["1:1-1:2"],"pagesRead":1.637041020126048,"secondsRead":417,"versesRead":24,"manuallyAddedSeconds":24,"dailyTargetPages":1.637041020126048,"dailyTargetSeconds":5,"dailyTargetRanges":["1:1-1:2"],"remainingDailyTargetRanges":["1:1-1:2"],"mushafId":4}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1GoalsGetTodaysPlan"}},"/v1/goals/{id}":{"put":{"description":"Update a goal","tags":["Goals"],"summary":"Update a goal","parameters":[{"in":"path","name":"id","schema":{"type":"string","description":"The id of the goal.","example":"cmoa3wr5c000g7z3fgv0y0rvo"},"required":true,"description":"The id of the goal."},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["QURAN_TIME","QURAN_PAGES","QURAN_RANGE","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The type of the goal.","example":"QURAN_TIME"},"amount":{"oneOf":[{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$","example":"1:5-1:10","x-required":true},{"type":"integer","minimum":1,"example":600,"x-required":true}],"description":"The amount of the goal. Depending on the goal type, the amount value and format will be different"},"duration":{"type":"integer","minimum":1,"description":"The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."},"category":{"type":"string","enum":["QURAN","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The category of the goal"}},"additionalProperties":false},"example":{"type":"QURAN_TIME","amount":"1:5-1:10","duration":1,"category":"QURAN"}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPutV1GoalsById"},"delete":{"description":"Delete a goal by id.","tags":["Goals"],"summary":"Delete a goal","parameters":[{"in":"path","name":"id","schema":{"type":"string","description":"The id of the goal.","example":"cmoa3wr5c000g7z3fgv0y0rvo"},"required":true,"description":"The id of the goal."},{"in":"query","name":"category","schema":{"type":"string","enum":["QURAN","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The category of the goal"},"required":true,"description":"The category of the goal"},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"message":{"enum":["goal deleted"]}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"message":"goal deleted"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authDeleteV1GoalsById"}},"/v1/goals":{"post":{"description":"Create a goal","tags":["Goals"],"summary":"Create a goal","parameters":[{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["QURAN_TIME","QURAN_PAGES","QURAN_RANGE","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The type of the goal.","example":"QURAN_TIME"},"amount":{"oneOf":[{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$","example":"1:5-1:10","x-required":true},{"type":"integer","minimum":1,"example":600,"x-required":true}],"description":"The amount of the goal. Depending on the goal type, the amount value and format will be different"},"duration":{"type":"integer","minimum":1,"description":"The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."},"category":{"type":"string","enum":["QURAN","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The category of the goal"}},"required":["type","amount","category"],"additionalProperties":false},"example":{"type":"QURAN_TIME","amount":"1:5-1:10","duration":1,"category":"QURAN"}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"The id of the goal.","example":"cmoa3wr5c000g7z3fgv0y0rvo"}},"required":["id"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"id":"cmoa3wr5c000g7z3fgv0y0rvo"}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1Goals"}},"/v1/goals/estimate":{"get":{"description":"Generate a timeline up to a week of the minimum daily amount required to meet the goal.","tags":["Goals"],"summary":"Generate timeline estimation","parameters":[{"in":"query","name":"type","schema":{"type":"string","enum":["QURAN_TIME","QURAN_PAGES","QURAN_RANGE","COURSE","QURAN_READING_PROGRAM","RAMADAN_CHALLENGE"],"description":"The type of the goal.","example":"QURAN_TIME"},"required":true,"description":"The type of the goal."},{"in":"query","name":"amount","schema":{"oneOf":[{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$","example":"1:5-1:10","x-required":true},{"type":"integer","minimum":1,"example":600,"x-required":true}],"description":"The amount of the goal. Depending on the goal type, the amount value and format will be different"},"required":true,"description":"The amount of the goal. Depending on the goal type, the amount value and format will be different"},{"in":"query","name":"duration","schema":{"type":"integer","minimum":1,"description":"The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."},"required":false,"description":"The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."},{"in":"query","name":"mushafId","schema":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4},"required":true,"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/EstimatedGoalTimeline"}},"additionalProperties":false},"example":{"success":true,"data":{"week":[{"date":"2023-01-21T07:28:13.023Z","amount":"1:5-1:10"}]}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1GoalsEstimate"}},"/v1/streaks":{"get":{"description":"Get user streaks.","tags":["Streaks"],"summary":"Get streaks","parameters":[{"in":"query","name":"from","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date after which any streaks would be returned (inclusive)","example":"2023-09-01"},"description":"The date after which any streaks would be returned (inclusive)"},{"in":"query","name":"to","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date before which any streaks would be returned (inclusive)","example":"2023-09-31"},"description":"The date before which any streaks would be returned (inclusive)"},{"in":"query","name":"type","schema":{"type":"string","enum":["QURAN"],"description":"The type of the streak","example":"QURAN"},"description":"The type of the streak"},{"in":"query","name":"sortOrder","schema":{"type":"string","enum":["asc","desc"],"description":"The sorting order of `orderBy` field","example":"desc","default":"desc"},"description":"The sorting order of `orderBy` field"},{"in":"query","name":"orderBy","schema":{"type":"string","enum":["startDate","days"],"description":"Which field to order the streaks by","example":"startDate","default":"startDate"},"description":"Which field to order the streaks by"},{"in":"query","name":"status","schema":{"type":"string","enum":["ACTIVE","BROKEN"],"description":"The status of the streak.","example":"ACTIVE"},"description":"The status of the streak."},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The id of the streak.","example":"cmoa3wrr2000i7z3fe8swbujv"},"startDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date of the streak.","example":"2023-09-01"},"endDate":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date of the streak.","example":"2023-09-31"},"status":{"type":"string","enum":["ACTIVE","BROKEN"],"description":"The status of the streak.","example":"ACTIVE"},"days":{"type":"integer","description":"The number of days the streak is/was active for.","example":5}},"required":["id","startDate","endDate","status","days"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wrr2000i7z3fe8swbujv","startDate":"2023-09-01","endDate":"2023-09-31","status":"ACTIVE","days":5}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1Streaks"}},"/v1/streaks/current-streak-days":{"get":{"description":"Get current active streak days.","tags":["Streaks"],"summary":"Get current streak days","parameters":[{"in":"query","name":"type","schema":{"type":"string","enum":["QURAN"],"description":"The type of the streak","example":"QURAN"},"required":true,"description":"The type of the streak"},{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"days":{"type":"integer","description":"The number of days the current streak is active for.","example":5}},"required":["days"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"days":5}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1StreaksCurrentStreakDays"}},"/v1/activity-days":{"post":{"description":"Create or update a daily activity record (one per date per type). Activity Days power streaks, goals, and calendar-style progress.\n\nFor `type=QURAN`, provide `seconds`, `ranges`, and `mushafId`. You can optionally pass `date` (YYYY-MM-DD) to backfill activity for a past day (for example when the user manually adds time). This endpoint enqueues progress updates and uses the `x-timezone` header to interpret day boundaries and calculate streaks accurately.","tags":["Activity Days"],"summary":"Add/update activity day","parameters":[{"in":"header","name":"x-timezone","schema":{"type":"string","description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.","example":"Asia/Saigon"},"description":"The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date of the activity day, can be today or a past date. If not passed, default to today","example":"2023-09-01"},"type":{"type":"string","enum":["QURAN","LESSON","QURAN_READING_PROGRAM"],"description":"The type of the activity day","example":"QURAN"}},"required":["type"],"additionalProperties":false,"oneOf":[{"type":"object","properties":{"seconds":{"type":"integer","minimum":1,"description":"Seconds spent reading the current request's ranges","example":5},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"},"description":"Current request's read range of Ayahs","example":["1:5-1:10"]},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4}},"required":["seconds","ranges","mushafId"],"additionalProperties":false,"title":"QURAN"}]},"example":{"seconds":5,"ranges":["1:5-1:10"],"mushafId":4}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object"}},"additionalProperties":false},"example":{"success":true,"data":{}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1ActivityDays"},"get":{"description":"Get the user's activity days (calendar/history). Use the `from`/`to` query params to filter by date range and `type` to filter by activity type.","tags":["Activity Days"],"summary":"Get activity days","parameters":[{"in":"query","name":"from","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The start date of the activity days","example":"2023-09-01"},"description":"The start date of the activity days"},{"in":"query","name":"to","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The last date of the activity days","example":"2023-09-31"},"description":"The last date of the activity days"},{"in":"query","name":"dateOrderBy","schema":{"type":"string","enum":["asc","desc"],"description":"Order by activity day's date","example":"desc","default":"desc"},"description":"Order by activity day's date"},{"in":"query","name":"type","schema":{"type":"string","enum":["QURAN","LESSON","QURAN_READING_PROGRAM"],"description":"The type of the activity day","example":"QURAN"},"description":"The type of the activity day"},{"in":"query","name":"last","schema":{"type":"integer","minimum":1,"maximum":20,"description":"The number of items to be fetched. Should be used together with `before`","example":10},"description":"The number of items to be fetched. Should be used together with `before`"},{"in":"query","name":"first","schema":{"type":"integer","minimum":1,"maximum":20,"oneOf":[{"type":"integer"}],"description":"The number of items to be fetched.","example":10},"description":"The number of items to be fetched."},{"in":"query","name":"after","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor after which you want to get the next page of items. Should be used together with `first`","example":"cmoa3wq0z00007z3fh1v9g30d"},"description":"The cursor after which you want to get the next page of items. Should be used together with `first`"},{"in":"query","name":"before","schema":{"type":"string","oneOf":[{"type":"string"}],"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`","example":"cmoa3wq1000017z3f9atfhuvw"},"description":"The cursor before which the previous page of items will be fetched. Should be used together with `last`"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The id of the activity day.","example":"cmoa3wq2b00047z3fbl4c6ew0"},"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"The date of the activity day.","example":"2023-09-31"},"progress":{"type":"number","format":"float","minimum":0,"maximum":1,"description":"The progress of the reading goal of that activity day (if the user has a reading goal on that day).","example":0.695},"type":{"type":"string","enum":["QURAN","LESSON","QURAN_READING_PROGRAM"],"description":"The type of the activity day","example":"QURAN"},"ranges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The ranges read on that day (will be included only when the type is QURAN)","example":["1:1-1:2"]},"pagesRead":{"oneOf":[{"type":"number","format":"float"}],"description":"The number of pages read on that day (will be included only when the type is QURAN)","example":1.637041020126048},"secondsRead":{"oneOf":[{"type":"integer"}],"description":"The number of seconds spent reading on that day (will be included only when the type is QURAN)","example":417},"versesRead":{"oneOf":[{"type":"integer"}],"description":"The number of Ayahs read on that day (will be included only when the type is QURAN)","example":24},"manuallyAddedSeconds":{"oneOf":[{"type":"integer"}],"description":"The number of seconds spent reading that was manually input by the user and not auto-tracked (will be included only when the type is QURAN)","example":24},"dailyTargetPages":{"oneOf":[{"type":"number","format":"float"}],"description":"The number of pages user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":1.637041020126048},"dailyTargetSeconds":{"oneOf":[{"type":"integer"}],"description":"The number of seconds user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":5},"dailyTargetRanges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":["1:1-1:2"]},"remainingDailyTargetRanges":{"oneOf":[{"type":"array","items":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"}}],"description":"The remaining range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)","example":["1:1-1:2"]},"mushafId":{"type":"integer","enum":[1,2,3,4,5,6,7,11,19],"description":"The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4","example":4}},"required":["id","date","progress","type","mushafId"],"additionalProperties":false,"description":"The Mushaf used to read on that day (will be included only when the type is QURAN) \n\nThe id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"cmoa3wq2b00047z3fbl4c6ew0","date":"2023-09-31","progress":0.695,"type":"QURAN","ranges":["1:1-1:2"],"pagesRead":1.637041020126048,"secondsRead":417,"versesRead":24,"manuallyAddedSeconds":24,"dailyTargetPages":1.637041020126048,"dailyTargetSeconds":5,"dailyTargetRanges":["1:1-1:2"],"remainingDailyTargetRanges":["1:1-1:2"],"mushafId":4}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1ActivityDays"}},"/v1/activity-days/estimate-reading-time":{"get":{"description":"Estimate the number of seconds it would take to read a range. We estimate it based on the average reading speed we have collected on quran.com.","tags":["Activity Days"],"summary":"Estimate reading time","parameters":[{"in":"query","name":"ranges","schema":{"type":"string","pattern":"^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$","description":"a comma separated string of Ayah ranges e.g. 1:1-1:2","example":"1:1-1:2"},"required":true,"description":"a comma separated string of Ayah ranges e.g. 1:1-1:2"}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"seconds":{"type":"integer","description":"The number of seconds it would take on average to read the range of Ayahs.","example":66.8}},"required":["seconds"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"seconds":66.8}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1ActivityDaysEstimateReadingTime"}},"/v1/users/profile":{"patch":{"operationId":"UsersController_editProfile","summary":"Edit user profile","description":"Partially update the authenticated user settings and preferences like notification settings, privacy options, and display preferences.","parameters":[],"requestBody":{"required":true,"description":"Settings fields to update - only include fields you want to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditProfileDto"},"example":{"languageId":1,"reflectionLanguages":["string"],"ayahLanguages":["string"],"customized":true,"hideFollowSuggestion":true,"showFollowFeaturedSuggestion":true}}}},"responses":{"200":{"description":"Settings updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}},"example":{"success":true}}}},"400":{"description":"Invalid settings data"},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"get":{"operationId":"UsersController_profile","summary":"Get user profile","description":"Retrieve the complete profile of the authenticated user including personal info, settings, statistics, and connected accounts.","parameters":[{"name":"qdc","required":false,"in":"query","description":"Include Quran.com (QDC) connected account data","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Full user profile with all data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSerializedDto"},"example":{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}}}},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"put":{"operationId":"UsersController_updateProfile","summary":"Update user profile","description":"Update user profile information including name, bio, username, avatar, and social links. Validates username uniqueness.","parameters":[],"requestBody":{"required":true,"description":"Profile fields to update wrapped in a user object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProfileBodyDto"},"example":{"user":{"avatar":"string","firstName":"string","lastName":"string","bio":"string","country":"string","removeAvatar":true}}}}},"responses":{"200":{"description":"Profile updated and returned with new values","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSerializedDto"},"example":{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}}}},"400":{"description":"Invalid profile data or username taken"},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/notes":{"get":{"tags":["Notes"],"description":"List notes owned by the user. This API contains pagination. Read more about [pagination](/#pagination)","summary":"Get all notes","parameters":[{"in":"query","name":"cursor","schema":{"type":"string","description":"A cursor for pagination, used to fetch the next set of results.","example":"cursor123"},"description":"A cursor for pagination, used to fetch the next set of results."},{"in":"query","name":"limit","schema":{"type":"number","format":"float","minimum":1,"maximum":50,"description":"The maximum number of notes to return, defaults to 20.","example":20,"default":20},"description":"The maximum number of notes to return, defaults to 20."},{"in":"query","name":"sortBy","schema":{"type":"string","enum":["newest","oldest"],"description":"The sorting order of the notes, defaults to newest first.","example":"newest","default":"newest"},"description":"The sorting order of the notes, defaults to newest first."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1Notes"},"post":{"tags":["Notes"],"description":"Add a new note.","summary":"Add note","parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"saveToQR":{"type":"boolean","description":"Indicates whether the note should be saved to the QuranReflect.","example":true},"attachedEntity":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["body","saveToQR"],"additionalProperties":false},"example":{"body":"This is a sample note body.","saveToQR":true,"attachedEntity":{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}},"ranges":["2:255-2:257"]}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1Notes"}},"/v1/notes/by-verse/{verseKey}":{"get":{"tags":["Notes"],"description":"Retrieve notes by a specific verse.","summary":"Get notes by verse","parameters":[{"in":"query","name":"verseKey","schema":{"type":"string","pattern":"^(\\d+):(\\d+)$","description":"The verse key for which notes are being requested.","example":"2:255"},"required":true,"description":"The verse key for which notes are being requested."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"startCursor":{"type":"string","example":"cmoa3wq1000027z3fciij2440"},"endCursor":{"type":"string","example":"cmoa3wq1000037z3fhr8z3edp"},"hasNextPage":{"type":"boolean","example":true},"hasPreviousPage":{"type":"boolean","example":false}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}],"pagination":{"startCursor":"cmoa3wq1000027z3fciij2440","endCursor":"cmoa3wq1000037z3fhr8z3edp","hasNextPage":true,"hasPreviousPage":false}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1NotesByVerseByVerseKey"}},"/v1/notes/by-attached-entity":{"get":{"tags":["Notes"],"description":"Retrieve notes by attached entity.","summary":"Get notes by attached entity","parameters":[{"in":"query","name":"entityId","schema":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"required":true,"description":"The unique identifier for the attached entity."},{"in":"query","name":"entityType","schema":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"required":true,"description":"The type of the attached entity, must be one of the predefined NoteEntityType values."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}]}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1NotesByAttachedEntity"}},"/v1/notes/count-within-range":{"get":{"tags":["Notes"],"description":"Get the count of notes within a range of verses.","summary":"Get notes count within verse range","parameters":[{"in":"query","name":"from","schema":{"type":"string","pattern":"^(\\d+):(\\d+)$","description":"The starting verse key of the range.","example":"2:12"},"required":true,"description":"The starting verse key of the range."},{"in":"query","name":"to","schema":{"type":"string","pattern":"^(\\d+):(\\d+)$","description":"The ending verse key of the range.","example":"2:18"},"required":true,"description":"The ending verse key of the range."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{},"additionalProperties":{"type":"integer","minimum":1},"description":"A map of verse keys to note counts, where each key is a verse key and each value is an integer count of notes.","example":{"1:2":5,"1:3":1,"1:4":1}}},"additionalProperties":false},"example":{"success":true,"data":{"1:2":5,"1:3":1,"1:4":1}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1NotesCountWithinRange"}},"/v1/notes/by-range":{"get":{"tags":["Notes"],"description":"Retrieve notes by a range of verses.","summary":"Get notes by verse range","parameters":[{"in":"query","name":"from","schema":{"type":"string","pattern":"^(\\d+):(\\d+)$","description":"The starting verse key of the range.","example":"2:12"},"required":true,"description":"The starting verse key of the range."},{"in":"query","name":"to","schema":{"type":"string","pattern":"^(\\d+):(\\d+)$","description":"The ending verse key of the range.","example":"2:18"},"required":true,"description":"The ending verse key of the range."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}}},"additionalProperties":false},"example":{"success":true,"data":[{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}]}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1NotesByRange"}},"/v1/notes/{noteId}":{"get":{"tags":["Notes"],"description":"Retrieve a note by its ID.","summary":"Get note by ID","parameters":[{"in":"query","name":"withAttachedEntities","schema":{"type":"boolean","description":"Specifies whether to include attached entities in the response, defaults to true.","example":true,"default":true},"description":"Specifies whether to include attached entities in the response, defaults to true."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authGetV1NotesByNoteId"},"patch":{"tags":["Notes"],"description":"Update a note by its ID.","summary":"Update note by ID","parameters":[{"in":"path","name":"noteId","schema":{"type":"string","description":"The unique identifier of the note to be retrieved or manipulated.","example":"asda12312312"},"required":true,"description":"The unique identifier of the note to be retrieved or manipulated."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"saveToQR":{"type":"boolean","description":"Indicates whether the updated note should be saved to the QuranReflect, defaults to false.","example":false,"default":false}},"required":["body"],"additionalProperties":false},"example":{"body":"This is a sample note body.","saveToQR":false}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"The unique identifier of the note.","example":"asdasdqwe1231"},"createdAt":{"type":"string","format":"date-time","description":"The creation date of the note.","example":"2023-01-21T07:28:13.023Z"},"updatedAt":{"type":"string","format":"date-time","description":"The last update date of the note.","example":"2023-01-22T07:28:13.023Z"},"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"source":{"type":"string","description":"The source of the note.","example":"we23412312weq"},"attachedEntities":{"type":"array","items":{"type":"object","properties":{"entityId":{"type":"string","description":"The unique identifier for the attached entity.","example":"entity123"},"entityType":{"type":"string","enum":["reflection"],"description":"The type of the attached entity, must be one of the predefined NoteEntityType values.","example":"reflection"},"entityMetadata":{"type":"object","properties":{},"description":"Additional metadata for the attached entity.","example":{"key":"value"}}},"required":["entityId","entityType"],"additionalProperties":false},"description":"An array of attached entities associated with the note."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:255-2:257"]}},"required":["id","createdAt","updatedAt","body"],"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"id":"asdasdqwe1231","createdAt":"2023-01-21T07:28:13.023Z","updatedAt":"2023-01-22T07:28:13.023Z","body":"This is a sample note body.","source":"we23412312weq","attachedEntities":[{"entityId":"entity123","entityType":"reflection","entityMetadata":{"key":"value"}}],"ranges":["2:255-2:257"]}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPatchV1NotesByNoteId"},"delete":{"tags":["Notes"],"description":"Delete a note by its ID.","summary":"Delete note by ID","parameters":[{"in":"path","name":"noteId","schema":{"type":"string","description":"The ID of the note to delete."},"required":true,"description":"The ID of the note to delete."}],"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"success":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false},"example":{"success":true,"data":{"success":true}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authDeleteV1NotesByNoteId"}},"/v1/notes/{noteId}/publish":{"post":{"tags":["Notes"],"description":"Publish a note to QR.","summary":"Publish note","parameters":[{"in":"path","name":"noteId","schema":{"type":"string","description":"The unique identifier of the note to be retrieved or manipulated.","example":"asda12312312"},"required":true,"description":"The unique identifier of the note to be retrieved or manipulated."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":6,"maxLength":10000,"description":"The main content of the note, must be between the specified minimum and maximum length.","example":"This is a sample note body."},"ranges":{"type":"array","items":{"type":"string","pattern":"^(\\d+):(\\d+)-(\\d+):(\\d+)$"},"description":"An array of verse ranges associated with the note.","example":["2:112-2:115"]}},"required":["body"],"additionalProperties":false},"example":{"body":"This is a sample note body.","ranges":["2:112-2:115"]}}}},"responses":{"200":{"description":"Request has been handled successfully.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"success":{"type":"boolean"},"postId":{"type":"number","format":"float"}},"required":["success"],"additionalProperties":false,"description":"Response object indicating the success of the note publishing operation and the optional post ID if successful.","example":{"success":true,"postId":123}}},"additionalProperties":false},"example":{"success":true,"data":{"success":true,"postId":123}}}}},"400":{"description":"The request is missing required parameters or is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request is missing required headers or is invalid"},"type":{"type":"string","example":"invalid_request"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"401":{"description":"The request is unauthorized.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request requires user authentication"},"type":{"type":"string","example":"unauthorized"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"403":{"description":"Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server understood the request, but refuses to authorize it"},"type":{"type":"string","example":"forbidden"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"404":{"description":"Not Found. The resource being accessed does not exist.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The requested resource could not be found"},"type":{"type":"string","example":"not_found"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"422":{"description":"Validation Error. The request includes one or more invalid params. Please check the request params and try again.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The request was well-formed but was unable to be followed due to semantic errors"},"type":{"type":"string","example":"unprocessable_entity"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"429":{"description":"Too many requests, please try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Too many requests, please try again later"},"type":{"type":"string","example":"rate_limit_exceeded"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"500":{"description":"Server Error. Something went wrong, try again later.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server encountered an internal error and was unable to complete your request"},"type":{"type":"string","example":"internal_server_error"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"502":{"description":"Invalid response from the upstream server","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and received an invalid response from the upstream server"},"type":{"type":"string","example":"bad_gateway"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"503":{"description":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"},"type":{"type":"string","example":"service_unavailable"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}},"504":{"description":"The server did not receive a timely response from the upstream server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"},"type":{"type":"string","example":"gateway_timeout"},"success":{"type":"boolean","example":false}},"additionalProperties":false}}}}},"operationId":"authPostV1NotesByNoteIdPublish"}},"/v1/users/my-rooms":{"get":{"operationId":"UsersController_rooms","summary":"Get logged-in user rooms","description":"Retrieve all rooms (groups and pages) the authenticated user is a member of. Supports filtering by name and pagination.","parameters":[{"name":"name","required":false,"in":"query","description":"Filter rooms by name","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Rooms per page (default: 10)","schema":{"type":"number"}}],"responses":{"200":{"description":"User rooms with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRoomsResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"id":1,"name":"string","group":"string","public":true,"roomType":"string","verified":true,"subdomain":"string","description":"string","membersCount":1,"avatarUrl":{"small":"string","medium":"string","large":"string"}}]}}}},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/search":{"get":{"operationId":"UsersController_search","summary":"Search for users","description":"Search users by name or username. Supports mentioning in posts, finding users for room invites, and general discovery. Results can be scoped to specific contexts.","parameters":[{"name":"query","required":false,"in":"query","description":"Search term for name/username","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Results per page (default: 10)","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}},{"name":"all","required":false,"in":"query","description":"Search all users (not just followed)","schema":{"type":"boolean"}},{"name":"postingAs","required":false,"in":"query","description":"Filter for posting-as feature","schema":{"type":"boolean"}},{"name":"postingAsUserId","required":false,"in":"query","description":"User ID for posting-as context","schema":{"type":"string"}},{"name":"roomId","required":false,"in":"query","description":"Room ID for scoped search","schema":{"type":"number"}}],"responses":{"200":{"description":"Matching users with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersSearchResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"isFollowed":false,"followed":false,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string"}]}}}}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{followeeId}/toggle-follow":{"post":{"operationId":"UsersController_toggleFollow","summary":"Toggle follow/unfollow a user","description":"Follow or unfollow another user. When following, their posts will appear in your FOLLOWING feed. Can optionally specify action to force follow/unfollow.","parameters":[{"name":"followeeId","required":true,"in":"path","description":"UUID of the user to follow/unfollow","schema":{"type":"string"}}],"requestBody":{"required":false,"description":"Optional: specify \"follow\" or \"unfollow\" action explicitly","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleFollowDto"},"example":{"action":"follow"}}}},"responses":{"200":{"description":"Follow status changed - returns new state","content":{"application/json":{"schema":{"type":"object","properties":{"followed":{"type":"boolean","description":"true if now following"}}},"example":{"followed":true}}}},"400":{"description":"Cannot follow yourself or action already in desired state"},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{followerId}/remove-follower":{"post":{"operationId":"UsersController_removeFollower","summary":"Remove a follower","description":"Remove a user from your followers list. They will no longer see you as followed and won't receive notifications about your activity.","parameters":[{"name":"followerId","required":true,"in":"path","description":"UUID of the follower to remove","schema":{"type":"string"}}],"responses":{"200":{"description":"Follower removed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean","example":true}}},"example":{"removed":true}}}},"400":{"description":"Invalid follower id or follower relationship doesn't exist"},"401":{"description":"User not authenticated"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{id}":{"get":{"operationId":"UsersController_getUserProfile","summary":"Get user profile by id or username","description":"Retrieve a user profile by either UUID or username. If viewing your own profile, returns full data; otherwise returns public profile with follow relationship status.","parameters":[{"name":"id","required":false,"in":"path","description":"UUID of the user","schema":{"type":"string"}},{"name":"username","required":false,"in":"path","description":"Username of the user (case-insensitive)","schema":{"type":"string"}},{"name":"qdc","required":false,"in":"query","description":"Include Quran.com connected account data","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Own profile with full data including settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSerializedDto"},"example":{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}}}},"404":{"description":"User not found"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{username}/profile":{"get":{"operationId":"UsersController_getUserProfile","summary":"Get user profile by id or username","description":"Retrieve a user profile by either UUID or username. If viewing your own profile, returns full data; otherwise returns public profile with follow relationship status.","parameters":[{"name":"id","required":false,"in":"path","description":"UUID of the user","schema":{"type":"string"}},{"name":"username","required":false,"in":"path","description":"Username of the user (case-insensitive)","schema":{"type":"string"}},{"name":"qdc","required":false,"in":"query","description":"Include Quran.com connected account data","schema":{"type":"boolean"}}],"responses":{"200":{"description":"Own profile with full data including settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSerializedDto"},"example":{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}}}},"404":{"description":"User not found"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{id}/followers":{"get":{"operationId":"UsersController_getUserFollowers","summary":"Get user followers","description":"Retrieve a paginated list of users who follow the specified user. Includes follow relationship to the viewer if authenticated.","parameters":[{"name":"id","required":true,"in":"path","description":"UUID of the user","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Results per page (default: 10)","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}}],"responses":{"200":{"description":"List of followers with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersSearchResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"isFollowed":false,"followed":false,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string"}]}}}},"404":{"description":"User not found"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/users/{id}/following":{"get":{"operationId":"UsersController_getUserFollowing","summary":"Get users followed by user","description":"Retrieve a paginated list of users that the specified user follows. Includes follow relationship to the viewer if authenticated.","parameters":[{"name":"id","required":true,"in":"path","description":"UUID of the user","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Results per page (default: 10)","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}}],"responses":{"200":{"description":"List of followed users with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersSearchResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"isFollowed":false,"followed":false,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string"}]}}}},"404":{"description":"User not found"}},"tags":["Users"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/admins-access":{"post":{"operationId":"RoomsController_adminsAccess","summary":"Update room admin access","description":"Grant or revoke admin privileges for a user in a room. Only room owners or existing admins can modify admin access.","parameters":[],"requestBody":{"required":true,"description":"Contains roomId, userId, and admin boolean to grant/revoke access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomAdminUpdateDto"},"example":{"roomId":1,"userId":"string","admin":true}}}},"responses":{"200":{"description":"Admin access updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}},"example":{"success":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to modify admin access"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/groups":{"patch":{"operationId":"RoomsController_updateGroup","summary":"Update a group","description":"Update group properties like name, description, URL, avatar, country, or public visibility. Only group admins/owners can update.","parameters":[],"requestBody":{"required":true,"description":"Group fields to update - all fields optional except id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGroupDto"},"example":{"id":1,"name":"string","description":"string","url":"string","removeAvatar":true,"avatar":"string","country":"string","public":null}}}},"responses":{"200":{"description":"Group updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"room":{"type":"object"}}},"example":{"success":true,"room":{}}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to update this group"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"post":{"operationId":"RoomsController_createNewGroup","summary":"Create a new group","description":"Create a new community group for sharing reflections. Groups can be public or private, and the creator becomes the owner.","parameters":[],"requestBody":{"required":true,"description":"Group creation details including name, description, URL, and visibility","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupDto"},"example":{"name":"string","description":"string","url":"string","public":true}}}},"responses":{"201":{"description":"Group created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomCreatedResponseDto"},"example":{"success":true,"data":{"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}}}}},"400":{"description":"Invalid group data or URL already taken"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/pages":{"patch":{"operationId":"RoomsController_updatePage","summary":"Update a page","description":"Update page properties like name, description, contact info, organization details, or visibility. Only page admins/owners can update.","parameters":[],"requestBody":{"required":true,"description":"Page fields to update - all fields optional except id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePageDto"},"example":{"id":1,"removeAvatar":true,"avatar":"string","public":null,"name":"string","description":"string","organizationWebsite":"string","country":"string","url":"string"}}}},"responses":{"200":{"description":"Page updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"room":{"type":"object"}}},"example":{"success":true,"room":{}}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to update this page"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"post":{"operationId":"RoomsController_createNewPage","summary":"Create a new page","description":"Submit a request to create a new organizational page. Pages require admin approval and include organization details, contact info, and purpose statement.","parameters":[],"requestBody":{"required":true,"description":"Page creation details including name, description, URL, organization info, and purpose","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePageDto"},"example":{"name":"string","description":"string","jobTitle":"string","contactNumber":"string","organizationName":"string","organizationWebsite":"string","purpose":"string","additionalDetails":"string","country":"string","url":"string","public":true}}}},"responses":{"201":{"description":"Page request submitted for admin review","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object"},"message":{"type":"string"}}},"example":{"success":true,"data":{},"message":"string"}}}},"400":{"description":"Invalid page data or URL already taken"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/members":{"get":{"operationId":"RoomsController_getRoomMembers","summary":"Get room members","description":"Retrieve paginated list of members in a room (group or page). Returns user profiles with their roles.","parameters":[{"name":"limit","required":false,"in":"query","description":"Members per page (default: 10)","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}},{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Room members retrieved with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomMembersResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"id":"user-1","username":"member.username","firstName":"Member","lastName":"User","verified":true,"avatarUrls":{"small":"https://avatars.quran.foundation/users/user-1/small.png","medium":"https://avatars.quran.foundation/users/user-1/medium.png","large":"https://avatars.quran.foundation/users/user-1/large.png"},"isAdmin":false,"isOwner":false,"isFollowed":true,"isActive":true,"followersCount":42}]}}}},"404":{"description":"Room not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/invite":{"post":{"operationId":"RoomsController_inviteUserToRoom","summary":"Invite user to room","description":"Send an invitation to a user to join the room. User will receive a notification/email with an invite link. Only admins can invite.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"User identification for invitation (email or userId)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteUserDto"},"example":{"userIds":["string"],"emails":["string"]}}}},"responses":{"200":{"description":"Invitation sent successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInviteUserResponseDto"},"example":{"invited":true,"inviteStatus":{"user-123":true,"user-456":"already_a_member"}}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to invite members"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/accept-invite":{"get":{"operationId":"RoomsController_acceptInvite","summary":"Accept room invite","description":"Accept an invitation to join a room using the token from the invite link. Adds user as member.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}},{"name":"token","required":true,"in":"query","description":"Invitation token from invite link","schema":{"type":"string"}}],"responses":{"200":{"description":"Invitation accepted - user is now a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInviteAcceptedResponseDto"},"example":{"accepted":true}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/reject-invite":{"get":{"operationId":"RoomsController_rejectInvite","summary":"Reject room invite","description":"Decline an invitation to join a room. Invalidates the invite token.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}},{"name":"token","required":true,"in":"query","description":"Invitation token from invite link","schema":{"type":"string"}}],"responses":{"200":{"description":"Invitation rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomInviteRejectedResponseDto"},"example":{"rejected":true}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/members/{userId}":{"delete":{"operationId":"RoomsController_removeMember","summary":"Remove member from room","description":"Remove a user from a room (group or page). Only admins can remove other members. Users can remove themselves.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}},{"name":"userId","required":true,"in":"path","description":"UUID of the user to remove","schema":{"type":"string"}}],"responses":{"200":{"description":"Member removed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}},"example":{"success":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to remove this member"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/joined-rooms":{"get":{"operationId":"RoomsController_getRooms","summary":"Get joined or managed rooms","description":"Retrieve rooms the user has joined (joined-rooms) or manages as admin (managed-rooms). Supports search and pagination.","parameters":[{"name":"query","required":false,"in":"query","description":"Search query for room names","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Rooms per page (default: 5)","schema":{"minimum":1,"maximum":5,"default":5,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Sort order (default: NAME_ASC)","schema":{"enum":["NAME_ASC","NAME_DESC","LATEST_ACTIVITY"],"type":"string"}}],"responses":{"200":{"description":"Rooms retrieved with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedRoomsResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}]}}}},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/managed-rooms":{"get":{"operationId":"RoomsController_getRooms","summary":"Get joined or managed rooms","description":"Retrieve rooms the user has joined (joined-rooms) or manages as admin (managed-rooms). Supports search and pagination.","parameters":[{"name":"query","required":false,"in":"query","description":"Search query for room names","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Rooms per page (default: 5)","schema":{"minimum":1,"maximum":5,"default":5,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Sort order (default: NAME_ASC)","schema":{"enum":["NAME_ASC","NAME_DESC","LATEST_ACTIVITY"],"type":"string"}}],"responses":{"200":{"description":"Rooms retrieved with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedRoomsResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}]}}}},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/search":{"get":{"operationId":"RoomsController_searchRooms","summary":"Search rooms","description":"Search for public groups and pages by name or description. Results can be filtered by room type.","parameters":[{"name":"query","required":false,"in":"query","description":"Search term for room name/description","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Results per page (default: 10)","schema":{"type":"number"}},{"name":"roomType","required":false,"in":"query","description":"Filter by room type: GROUP or PAGE","schema":{"type":"string"}}],"responses":{"200":{"description":"Matching rooms with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedRoomsResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}]}}}}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/group/{url}":{"get":{"operationId":"RoomsController_getRoomProfile","summary":"Get room profile by URL or subdomain","description":"Retrieve a room profile by its unique URL (for groups) or subdomain (for pages). Returns room details, member counts, and relationship status.","parameters":[{"name":"url","required":false,"in":"path","description":"Group URL identifier (lowercase)","schema":{"type":"string"}},{"name":"subdomain","required":false,"in":"path","description":"Page subdomain identifier (lowercase)","schema":{"type":"string"}}],"responses":{"200":{"description":"Room profile with details and membership info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomProfileResponseDto"},"example":{"privateToken":"private-room-token","mutualFollowers":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}],"mutualFollowersCount":2,"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}}}},"404":{"description":"Room not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/page/{subdomain}":{"get":{"operationId":"RoomsController_getRoomProfile","summary":"Get room profile by URL or subdomain","description":"Retrieve a room profile by its unique URL (for groups) or subdomain (for pages). Returns room details, member counts, and relationship status.","parameters":[{"name":"url","required":false,"in":"path","description":"Group URL identifier (lowercase)","schema":{"type":"string"}},{"name":"subdomain","required":false,"in":"path","description":"Page subdomain identifier (lowercase)","schema":{"type":"string"}}],"responses":{"200":{"description":"Room profile with details and membership info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomProfileResponseDto"},"example":{"privateToken":"private-room-token","mutualFollowers":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}],"mutualFollowersCount":2,"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}}}},"404":{"description":"Room not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/group/{url}/accept/{token}":{"get":{"operationId":"RoomsController_acceptByPrivateToken","summary":"Accept room invite by private token","description":"Accept an invitation using a private room URL with embedded token. Alternative to the /accept-invite endpoint for direct link access.","parameters":[{"name":"url","required":false,"in":"path","description":"Group URL identifier","schema":{"type":"string"}},{"name":"subdomain","required":false,"in":"path","description":"Page subdomain identifier","schema":{"type":"string"}},{"name":"token","required":true,"in":"path","description":"Private invitation token","schema":{"type":"string"}}],"responses":{"200":{"description":"Invitation accepted - user added to room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomAcceptByPrivateTokenResponseDto"},"example":{"roomId":42,"success":true,"isNewMember":true}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/page/{subdomain}/accept/{token}":{"get":{"operationId":"RoomsController_acceptByPrivateToken","summary":"Accept room invite by private token","description":"Accept an invitation using a private room URL with embedded token. Alternative to the /accept-invite endpoint for direct link access.","parameters":[{"name":"url","required":false,"in":"path","description":"Group URL identifier","schema":{"type":"string"}},{"name":"subdomain","required":false,"in":"path","description":"Page subdomain identifier","schema":{"type":"string"}},{"name":"token","required":true,"in":"path","description":"Private invitation token","schema":{"type":"string"}}],"responses":{"200":{"description":"Invitation accepted - user added to room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomAcceptByPrivateTokenResponseDto"},"example":{"roomId":42,"success":true,"isNewMember":true}}}},"400":{"description":"Invalid or expired token"},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}":{"get":{"operationId":"RoomsController_getRoomProfileById","summary":"Get room profile by ID","description":"Retrieve a room profile by its unique numeric ID. Returns room details, member counts, and relationship status for the current user.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Room profile retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomProfileResponseDto"},"example":{"privateToken":"private-room-token","mutualFollowers":[{"avatarUrls":{"small":"https://avatars.githubusercontent.com/u/12345678","medium":"https://avatars.githubusercontent.com/u/12345678","large":"https://avatars.githubusercontent.com/u/12345678"},"createdAt":"2000-01-21 00:00:00","joiningYear":2025,"isPasswordSet":true,"settings":{"ayahLanguages":[1],"reflectionLanguages":[1]},"username":"string","id":"string","verified":false,"postAs":false,"firstName":"string","lastName":"string","postsCount":0,"averageToxicity":0,"languageId":1,"banned":false,"memberType":1,"followersCount":0,"likesCount":0,"isAdmin":false,"languageIsoCode":"en","bio":"string","country":"string","followed":true}],"mutualFollowersCount":2,"id":1,"name":"string","description":"string","roomType":"string","isActive":true,"isVerified":true,"isPublic":true,"isOwner":true,"isAdmin":true,"ownerId":"string","postsCount":1,"membersCount":1,"url":"string","avatarUrls":{"thumb":"string","original":"string"},"createdAt":"2026-04-02T00:00:00.000Z","isMember":true,"subdomain":"string","country":"string"}}}},"404":{"description":"Room not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{id}/posts":{"get":{"operationId":"RoomsController_getRoomPosts","summary":"Get room posts","description":"Retrieve paginated posts shared within a room. Supports filtering by tab (REFLECTIONS, DISCUSSIONS) and sorting (LATEST, POPULAR).","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Sort order (default: latest)","schema":{"enum":["latest","popular"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Posts per page (max: 20)","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"tab","required":false,"in":"query","description":"Filter posts by content type","schema":{"enum":["reflections","saved","public","members_only"],"type":"string"}}],"responses":{"200":{"description":"Room posts with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}},"404":{"description":"Room not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{groupId}/join":{"post":{"operationId":"RoomsController_joinRoom","summary":"Join a group","description":"Join a public group as a member. For private groups, an invitation is required. Returns whether the join was successful.","parameters":[{"name":"groupId","required":true,"in":"path","description":"Unique numeric group ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Successfully joined the group","content":{"application/json":{"schema":{"type":"object","properties":{"joined":{"type":"boolean","example":true}}},"example":{"joined":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"Group is private - invitation required"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{groupId}/leave":{"post":{"operationId":"RoomsController_leaveGroup","summary":"Leave a group","description":"Leave a group the user is currently a member of. Owners cannot leave - they must transfer ownership first.","parameters":[{"name":"groupId","required":true,"in":"path","description":"Unique numeric group ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Successfully left the group","content":{"application/json":{"schema":{"type":"object","properties":{"left":{"type":"boolean","example":true}}},"example":{"left":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"Owner cannot leave - transfer ownership first"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{pageId}/follow":{"post":{"operationId":"RoomsController_followPage","summary":"Follow a page","description":"Follow an organizational page to see their posts in your feed. Pages represent verified organizations or scholars.","parameters":[{"name":"pageId","required":true,"in":"path","description":"Unique numeric page ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Successfully followed the page","content":{"application/json":{"schema":{"type":"object","properties":{"followed":{"type":"boolean","example":true}}},"example":{"followed":true}}}},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{pageId}/unfollow":{"post":{"operationId":"RoomsController_unfollowPage","summary":"Unfollow a page","description":"Stop following a page. Their posts will no longer appear in your personalized feed.","parameters":[{"name":"pageId","required":true,"in":"path","description":"Unique numeric page ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Successfully unfollowed the page","content":{"application/json":{"schema":{"type":"object","properties":{"unfollowed":{"type":"boolean","example":true}}},"example":{"unfollowed":true}}}},"401":{"description":"User not authenticated"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/rooms/{roomId}/posts/{postId}/privacy":{"patch":{"operationId":"RoomsController_updatePostPrivacy","summary":"Update post privacy in room","description":"Change the visibility of a post within a room. Toggle between public (visible outside room) and private (members only). Only admins can modify.","parameters":[{"name":"roomId","required":true,"in":"path","description":"Unique numeric room ID","schema":{"type":"number"}},{"name":"postId","required":true,"in":"path","description":"Unique numeric post ID","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Privacy setting with isPublic boolean","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoomPostUpdatePrivacyDto"},"example":{"isPublic":true}}}},"responses":{"200":{"description":"Post privacy updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostSerialized"},"example":{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to modify post privacy"},"404":{"description":"Room or post not found"}},"tags":["Rooms"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/feed":{"get":{"operationId":"PostsController_feed","summary":"Get posts feed","description":"Retrieve a paginated feed of Quran Reflect posts, including reflections and lessons. Supports filtering by authors, tags, Quran references, groups, pages, and post types. Response items include engagement metadata such as `likesCount`, `commentsCount`, and `recentComment` when available. Use the dedicated comment endpoints to retrieve comment objects and totals. For ayah-by-ayah reads, use `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`, and use `filter[postTypeIds]=1` for reflections or `filter[postTypeIds]=2` for lessons.","parameters":[{"name":"tab","required":false,"in":"query","description":"Feed tab type. `feed` shows personalized content, `trending` shows explore, and `following` shows posts from followed users.","schema":{"type":"string","enum":["newest","latest","following","draft","favorite","most_popular","only_room_members","public","feed","trending","popular"]}},{"name":"languages","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated list of language IDs to filter posts by reflection language, for example `languages=1,2`.","schema":{"type":"array","items":{"type":"number"},"example":[1,2]}},{"name":"page","required":false,"in":"query","description":"Page number for pagination (default: 1).","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of posts per page (default: 20).","schema":{"minimum":1,"default":20,"type":"number"}},{"name":"filter[verifiedOnly]","required":false,"in":"query","description":"Whether to limit the feed to verified contributors. Public ayah-by-ayah reads typically combine this with indexed reference filters such as `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`.","schema":{"type":"boolean","default":false,"example":true}},{"name":"filter[referencesOperator]","required":false,"in":"query","description":"Operator applied to multiple Quran reference filters.","schema":{"type":"string","enum":["OR","AND"]}},{"name":"filter[tagsOperator]","required":false,"in":"query","description":"Operator applied to multiple tag filters.","schema":{"type":"string","enum":["OR","AND"]}},{"name":"filter[postTypeIds]","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated Quran Reflect post type IDs. Use `1` for reflections and `2` for lessons.","schema":{"type":"array","items":{"type":"number"},"example":[1,2]}},{"name":"filter[pages]","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated list of page subdomains to include.","schema":{"type":"array","items":{"type":"string"},"example":["quran-reflections","khutbahapp"]}},{"name":"filter[groups]","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated list of group URLs to include.","schema":{"type":"array","items":{"type":"string"},"example":["my-group","ramadan-circle"]}},{"name":"filter[references][0][to]","required":false,"in":"query","description":"Ending ayah number for reference filter index `0`. For a single ayah, use the same value as `from`.","schema":{"type":"number","minimum":1,"example":255}},{"name":"filter[references][0][from]","required":false,"in":"query","description":"Starting ayah number for reference filter index `0`. Pair with the matching `chapterId` and `to` values.","schema":{"type":"number","minimum":1,"example":255}},{"name":"filter[references][0][chapterId]","required":false,"in":"query","description":"Reference filter example for index `0`. Use additional indices such as `filter[references][1][chapterId]` for more references.","schema":{"type":"number","minimum":1,"example":2}},{"name":"filter[tags]","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated list of tag values to include.","schema":{"type":"array","items":{"type":"string"},"example":["ramadan","patience"]}},{"name":"filter[authors]","required":false,"in":"query","style":"form","explode":false,"description":"Comma-separated list of author identifiers to include.","schema":{"type":"array","items":{"type":"string"},"example":["user-1","user-2"]}}],"responses":{"200":{"description":"Feed retrieved successfully with paginated posts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{postId}/related":{"get":{"operationId":"PostsController_getRelatedPosts","summary":"Get related posts","description":"Retrieve posts related to a given post by matching its Quran references with OR logic. Results are filtered by language preferences and ordered by popularity, excluding the source post.","parameters":[{"name":"postId","required":true,"in":"path","description":"Source post ID used for related-post matching","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of posts per page (default: 8, max: 8)","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination (default: 1)","schema":{"type":"number"}}],"responses":{"200":{"description":"Related posts retrieved successfully with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}},"404":{"description":"Source post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/my-posts":{"get":{"operationId":"PostsController_getLoggedinUserPosts","summary":"Get current user posts","description":"Retrieve posts created by the currently authenticated user. Supports filtering by tab (MY_REFLECTIONS, SAVED, DRAFTS), sorting options, and post type filtering.","parameters":[{"name":"tab","required":false,"in":"query","description":"Profile tab filter (default: my_reflections)","schema":{"enum":["my_reflections","saved","notes","mentions"],"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Sort order for posts (default: latest)","schema":{"enum":["latest","popular"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of posts per page (default: 20, max: 20)","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"postTypeIds","required":false,"in":"query","description":"Array of post type IDs to filter by","schema":{"type":"array","items":{"type":"number"}}}],"responses":{"200":{"description":"User posts retrieved successfully with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}},"401":{"description":"User not authenticated"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/liked":{"get":{"operationId":"PostsController_getLikedState","summary":"Get post liked state","description":"Returns whether the authenticated user currently likes the post. This lightweight endpoint avoids loading the full post payload for simple like-state checks.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to check liked state for","schema":{"type":"number"}}],"responses":{"200":{"description":"Like state retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"liked":{"type":"boolean","description":"true when the post is liked by the current user"}}},"example":{"liked":true}}}},"401":{"description":"User not authenticated"},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}":{"get":{"operationId":"PostsController_findOne","summary":"Get post by ID","description":"Retrieve a specific post by its unique numeric ID. Returns the full post with author details, tags, references, room information, and engagement metrics. Admins can view additional moderation details.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Post found and returned with all associated data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostSerialized"},"example":{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}}}},"404":{"description":"Post not found or has been deleted"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"delete":{"operationId":"PostsController_delete","summary":"Delete post","description":"Soft-delete a post by marking it as removed. Only the post author or admins can delete posts. Related engagement counts (likes, comments, saves) update asynchronously via background jobs, so metrics may briefly lag.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to delete","schema":{"type":"number"}}],"responses":{"200":{"description":"Post deletion accepted and queued for processing","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}},"example":{"success":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to delete this post"},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]},"patch":{"operationId":"PostsController_edit","summary":"Edit post","description":"Update an existing post. Only the post author or admins can edit. Supports updating body, references, mentions, draft status, and room visibility settings.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to update","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Partial post data to update - only include fields to change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePostDto"},"example":{"roomPostStatus":0,"body":"string","draft":true,"references":[{"chapterId":1,"from":0,"to":0}],"mentions":[{"marker":"{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}","userId":"string","displayName":"string"}],"roomId":1,"postAsAuthorId":"string","publishedAt":"2026-04-02T00:00:00.000Z"}}}},"responses":{"200":{"description":"Post updated successfully with the updated post data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCreatedResponse"},"example":{"data":{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"},"success":true}}}},"401":{"description":"User not authenticated"},"403":{"description":"User not authorized to edit this post"},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/viewed/{id}":{"get":{"operationId":"PostsController_viewTracking","summary":"Track post view","description":"Record that a post has been viewed by the current user (if authenticated). Used for analytics and engagement tracking. Does not require authentication but will track user-specific views when logged in.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID","schema":{"type":"number"}}],"responses":{"200":{"description":"View tracked successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}},"example":{"success":true}}}}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts":{"post":{"operationId":"PostsController_create","summary":"Create post","description":"Create a new post (reflection) with Quran references. Posts can be public, drafts, or associated with a room (group/page). Supports user mentions and multiple Quran verse references. Minimum body length is 6 characters.","parameters":[],"requestBody":{"required":true,"description":"Post creation payload containing the post object with body, references, mentions, and visibility settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePostBodyDto"},"example":{"post":{"roomPostStatus":0,"body":"string","draft":true,"references":[{"chapterId":1,"from":0,"to":0}],"mentions":[{"marker":"{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}","userId":"string","displayName":"string"}],"roomId":1,"postAsAuthorId":"string","publishedAt":"2026-04-02T00:00:00.000Z"}}}}},"responses":{"201":{"description":"Post created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCreatedResponse"},"example":{"data":{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"},"success":true}}}},"400":{"description":"Invalid post data - body too short, invalid references, or invalid room post status"},"401":{"description":"User not authenticated"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/report":{"post":{"operationId":"PostsController_reportAbuse","summary":"Report post abuse","description":"Report a post for moderation review. Provide a reason for the report to help moderators evaluate the content. Multiple reports on the same post may trigger automatic review.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to report","schema":{"type":"number"}}],"requestBody":{"required":true,"description":"Report details including reason for flagging the content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportAbuseBodyDto"},"example":{"report":{"abuse":"string","comments":""}}}}},"responses":{"200":{"description":"Report submitted successfully for moderation review","content":{"application/json":{"schema":{"type":"object","properties":{"reported":{"type":"boolean","example":true}}},"example":{"reported":true}}}},"401":{"description":"User not authenticated"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/user-posts/{id}":{"get":{"operationId":"PostsController_getUserPost","summary":"Get user posts","description":"Retrieve public posts created by a specific user. If viewing own posts while authenticated, returns all posts including drafts. Supports sorting and filtering by post type.","parameters":[{"name":"id","required":true,"in":"path","description":"UUID of the user whose posts to retrieve","schema":{"type":"string"}},{"name":"sortBy","required":false,"in":"query","description":"Sort order for posts (default: latest)","schema":{"enum":["latest","popular"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of posts per page (default: 20, max: 20)","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination (default: 1)","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"postTypeIds","required":false,"in":"query","description":"Array of post type IDs to filter by","schema":{"type":"array","items":{"type":"number"}}}],"responses":{"200":{"description":"User posts retrieved with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/toggle-like":{"post":{"operationId":"PostsController_toggleLike","summary":"Toggle post like","description":"Toggle like status for a post. If already liked, removes the like. If not liked, adds a like. Updates the post like count and triggers notifications.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to like/unlike","schema":{"type":"number"}}],"responses":{"200":{"description":"Like status toggled - returns new state","content":{"application/json":{"schema":{"type":"object","properties":{"liked":{"type":"boolean","description":"true if now liked, false if now unliked"}}},"example":{"liked":true}}}},"401":{"description":"User not authenticated"},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/toggle-save":{"post":{"operationId":"PostsController_toggleSave","summary":"Toggle post save","description":"Toggle save/bookmark status for a post. Saved posts appear in the SAVED tab of the user profile for easy access later.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID to save/unsave","schema":{"type":"number"}}],"responses":{"200":{"description":"Save status toggled - returns new state","content":{"application/json":{"schema":{"type":"object","properties":{"saved":{"type":"boolean","description":"true if now saved, false if now unsaved"}}},"example":{"saved":true}}}},"401":{"description":"User not authenticated"},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/comments":{"get":{"operationId":"PostsController_getComments","summary":"Get post comments","description":"Retrieve paginated top-level comments for a post. Use the replies endpoint to get nested replies for specific comments.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of results to return","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"default":1,"type":"number"}}],"responses":{"200":{"description":"Comments retrieved with pagination metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostCommentsResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"comments":[{"id":1,"postId":1,"authorId":"string","parentId":1,"isPrivate":false,"body":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","toxicityScore":1,"repliesCount":0,"likesCount":0,"reported":false,"removed":false,"hidden":false,"languageId":1,"languageName":"string","moderationStatus":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"tags":[{"language":"string","id":1,"name":"string","commentsCount":1}]}]}}}},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/{id}/all-comments":{"get":{"operationId":"PostsController_getAllComment","summary":"Get all post comments","description":"Retrieve all comments for a post in a single request without pagination. Useful for displaying full comment threads or export scenarios.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric post ID","schema":{"type":"number"}}],"responses":{"200":{"description":"All comments returned with total count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostAllCommentsResponse"},"example":{"comments":[{"id":1,"postId":1,"authorId":"string","parentId":1,"isPrivate":false,"body":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","toxicityScore":1,"repliesCount":0,"likesCount":0,"reported":false,"removed":false,"hidden":false,"languageId":1,"languageName":"string","moderationStatus":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"tags":[{"language":"string","id":1,"name":"string","commentsCount":1}]}],"total":"10 // works also with swagger setup"}}}},"404":{"description":"Post not found"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/export/pdf":{"post":{"operationId":"PostsController_exportMultiplePosts","summary":"Export posts as PDF","description":"Generate a downloadable PDF document containing selected posts with their full content, Quran references, and author information. Ayah translations are rendered according to user language preferences.","parameters":[],"requestBody":{"required":true,"description":"Array of post IDs to include in the PDF export (minimum 1)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportPostsDto"},"example":{"ids":[1,2,3]}}}},"responses":{"200":{"description":"PDF file generated and returned as binary attachment","content":{"application/pdf":{"schema":{"type":"string","format":"binary"},"example":"string"}}},"400":{"description":"Invalid request - empty or invalid post IDs array"},"401":{"description":"User not authenticated"},"404":{"description":"No accessible posts found for the given IDs"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/count-within-range":{"get":{"operationId":"PostsController_getMyPostsCountWithinRange","summary":"Get posts count within range","description":"Count how many posts the current user has written for verses within a specified Quran verse range. Useful for reading goals and progress tracking.","parameters":[{"name":"from","required":true,"in":"query","description":"Start verse key in format chapter:verse (e.g., \"2:1\")","schema":{"pattern":"VERSE_KEY_REGEX","example":"2:1","type":"string"}},{"name":"to","required":true,"in":"query","description":"End verse key in format chapter:verse (e.g., \"2:286\")","schema":{"pattern":"VERSE_KEY_REGEX","example":"2:286","type":"string"}}],"responses":{"200":{"description":"Count of posts within the specified verse range","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"number","example":5}}},"example":{"count":5}}}},"400":{"description":"Invalid verse range - malformed keys or from > to"},"401":{"description":"User not authenticated"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/posts/by-verse/{verseKey}":{"get":{"operationId":"PostsController_getMyPostsByVerse","summary":"Get posts by verse","description":"Retrieve all posts written by the current user for a specific Quran verse. This endpoint requires a user-bound token and returns only the authenticated user's own posts. It is not part of the public `client_credentials`-compatible read subset; for public ayah-by-ayah reads, use `GET /v1/posts/feed` with indexed reference filters such as `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`.","parameters":[{"name":"verseKey","required":true,"in":"path","description":"Verse key in format chapter:verse","schema":{"pattern":"VERSE_KEY_REGEX","example":"2:255","type":"string"}}],"responses":{"200":{"description":"User posts for the specified verse","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedResponseDto"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"data":[{"tags":[{"language":"string","id":1,"name":"string"}],"references":[{"id":"string","from":1,"to":1,"chapterId":1}],"author":{},"recentComment":{"id":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"body":"string","createdAt":"2026-04-02T00:00:00.000Z"},"room":{"isAdmin":{},"isOwner":{},"isPublic":{},"id":1,"subdomain":"string","roomType":"string","verified":false,"name":"string","_group":"string"},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"isLiked":true,"isByFollowedUser":true,"isCommentedOn":true,"isSaved":true,"id":1,"authorId":"string","body":"string","discussionId":1,"draft":false,"createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","publishedAt":"2026-04-02T00:00:00.000Z","global":true,"toxicityScore":1,"reported":false,"views":1,"removed":false,"verified":false,"roomPostStatus":0,"hidden":false,"commentsCount":0,"likesCount":0,"viewsCount":0,"languageId":1,"languageName":"string","moderationStatus":1,"reviewedAt":"2026-04-02T00:00:00.000Z","featuredAt":"2026-04-02T00:00:00.000Z","estimatedReadingTime":0,"roomId":1,"postTypeId":1,"postTypeName":"string"}]}}}},"400":{"description":"Invalid verse key format"},"401":{"description":"User not authenticated"}},"tags":["Posts"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/tags":{"get":{"operationId":"TagsController_find","summary":"Search and retrieve tags","description":"Search for tags by query string. Returns paginated results matching the search term. Useful for tag autocomplete and discovery features.","parameters":[{"name":"query","required":false,"in":"query","description":"Search term","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of results to return","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"type":"number"}}],"responses":{"200":{"description":"Tags matching search query with pagination","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}},"example":[{"id":1,"name":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","rank":0,"languageId":1,"languageName":"string","postsCount":1,"commentsCount":1}]}}}},"tags":["Tags"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/comments":{"post":{"operationId":"CommentsController_create","summary":"Create a new comment","description":"Add a comment to a post or reply to an existing comment. Supports mentions and notifies the post author.","parameters":[],"requestBody":{"required":true,"description":"Comment with postId and optional parentId","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentBody"},"example":{"comment":{"body":"This is a thoughtful comment about the post","postId":123,"isPrivate":false,"parentId":456,"mentions":[{"marker":"{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}","userId":"string","displayName":"string"}]}}}}},"responses":{"201":{"description":"Comment created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentResponse"},"example":{"comment":{"id":1,"postId":1,"authorId":"string","parentId":1,"isPrivate":false,"body":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","toxicityScore":1,"repliesCount":0,"likesCount":0,"reported":false,"removed":false,"hidden":false,"languageId":1,"languageName":"string","moderationStatus":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"tags":[{"language":"string","id":1,"name":"string","commentsCount":1}]},"success":true}}}},"400":{"description":"Invalid comment - empty body or invalid postId"},"401":{"description":"User not authenticated"},"404":{"description":"Post or parent comment not found"}},"tags":["Comments"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/comments/{id}/delete":{"get":{"operationId":"CommentsController_deleteComment","summary":"Delete a comment","description":"Soft-delete a comment and its direct replies. Only the comment owner, post owner, or admins can delete.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric comment ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Comment deleted","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"boolean","example":true}}},"example":{"removed":true}}}},"400":{"description":"User not authorized to delete this comment"},"401":{"description":"User not authenticated"},"404":{"description":"The comment has already been deleted"}},"tags":["Comments"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/comments/{id}/toggle-like":{"post":{"operationId":"CommentsController_toggleLike","summary":"Toggle like/unlike a comment","description":"Toggle like status. If liked, removes like. Notifies comment author on new likes.","parameters":[{"name":"id","required":true,"in":"path","description":"Unique numeric comment ID","schema":{"type":"number"}}],"responses":{"200":{"description":"Like toggled","content":{"application/json":{"schema":{"type":"object","properties":{"liked":{"type":"boolean","description":"true if liked, false if unliked"}}},"example":{"liked":true}}}},"401":{"description":"User not authenticated"},"404":{"description":"Comment not found"}},"tags":["Comments"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}},"/v1/comments/{id}/replies":{"get":{"operationId":"CommentsController_get","summary":"Get replies to a comment","description":"Retrieve paginated replies (nested comments) for a parent comment with author info.","parameters":[{"name":"id","required":true,"in":"path","description":"Parent comment ID","schema":{"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of results to return","schema":{"minimum":1,"maximum":20,"default":20,"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"default":1,"type":"number"}}],"responses":{"200":{"description":"Comment replies with pagination","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentRepliesResponse"},"example":{"total":10,"currentPage":1,"limit":10,"pages":1,"replies":[{"id":1,"postId":1,"authorId":"string","parentId":1,"isPrivate":false,"body":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","toxicityScore":1,"repliesCount":0,"likesCount":0,"reported":false,"removed":false,"hidden":false,"languageId":1,"languageName":"string","moderationStatus":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"tags":[{"language":"string","id":1,"name":"string","commentsCount":1}]}],"comment":{"id":1,"postId":1,"authorId":"string","parentId":1,"isPrivate":false,"body":"string","createdAt":"2026-04-02T00:00:00.000Z","updatedAt":"2026-04-02T00:00:00.000Z","toxicityScore":1,"repliesCount":0,"likesCount":0,"reported":false,"removed":false,"hidden":false,"languageId":1,"languageName":"string","moderationStatus":1,"author":{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1},"mentions":[{"postsCount":1,"avatarUrls":{"small":"string","medium":"string","large":"string"},"id":"string","username":"string","verified":false,"firstName":"string","lastName":"string","memberType":1,"locations":{},"followersCount":1,"displayName":"string"}],"tags":[{"language":"string","id":1,"name":"string","commentsCount":1}]}}}}},"404":{"description":"Parent comment not found"}},"tags":["Comments"],"servers":[{"url":"https://apis-prelive.quran.foundation/quran-reflect","description":"Pre-production Server"},{"url":"https://apis.quran.foundation/quran-reflect","description":"Production Server"}]}}}}
\ No newline at end of file
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "User-related APIs",
+ "version": "1.0.0",
+ "description": "Quran.Foundation user-related APIs enable your app to seamlessly integrate with Quran.Foundation's user-centric features, providing access to personalized notes, bookmarks, goals, streaks, reading sessions, and more. This differentiates them from [content APIs](/docs/category/content-apis) that focus on non-user-specific resources like translations, tafsirs, and verses.\n\n ## How to get access \n\n We are using OAuth2 flows to authenticate and authorize requests. To get started, you need to [get an access token](/docs/tutorials/oidc/getting-started-with-oauth2#obtaining-oauth-20-client-credentials) to make requests to our APIs. Then follow the steps mentioned [here](/docs/tutorials/oidc/getting-started-with-oauth2). \n\n For web applications, the recommended integration pattern is backend token exchange plus backend or server-side proxy calls to User APIs. Your app can keep the user session in secure server storage or `httpOnly` cookies, while your backend injects `x-auth-token` and `x-client-id` on outbound requests to Quran.Foundation APIs.\n\n ## Pagination \n\n We are using cursor based pagination. The pagination query params consist of `first`,`after`, `before` and `last`. \n\n Example \n - `first: 10` will give you first 10 items \n - `first: 10, after: xyz` will give you first 10 items after the item with id `xyz` \n - `last: 10` will give you the last 10 items \n - `last: 10, before: xyz` will give you the last 10 items before the item with id `xyz` \n\n The only possible combinations are `first + after` or `last + before`. They should not be used together"
+ },
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/auth",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/auth",
+ "description": "Production Server"
+ }
+ ],
+ "components": {
+ "securitySchemes": {
+ "x-auth-token": {
+ "type": "apiKey",
+ "in": "header",
+ "name": "x-auth-token",
+ "description": "The JWT access token required for accessing the endpoints."
+ },
+ "x-client-id": {
+ "type": "apiKey",
+ "in": "header",
+ "name": "x-client-id",
+ "description": "Your client id"
+ }
+ },
+ "schemas": {
+ "NullableBookmark": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wqim00057z3fe30y0b3e"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "type": {
+ "type": "string",
+ "example": "ayah"
+ },
+ "key": {
+ "type": "integer",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "nullable": true,
+ "example": 5
+ },
+ "group": {
+ "type": "string",
+ "example": "verses_6236"
+ },
+ "isInDefaultCollection": {
+ "type": "boolean",
+ "example": true
+ },
+ "isReading": {
+ "type": "boolean",
+ "nullable": true,
+ "example": false
+ },
+ "collectionsCount": {
+ "type": "integer",
+ "description": "Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.",
+ "example": 1
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "type",
+ "key",
+ "group",
+ "isInDefaultCollection",
+ "isReading"
+ ],
+ "additionalProperties": false,
+ "nullable": true
+ },
+ "RawBookmark": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wqiu00067z3fh6oieeiq"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "bookmarkType": {
+ "oneOf": [
+ {
+ "type": "string",
+ "example": "ayah"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "example": "ayah"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ }
+ ]
+ },
+ "key": {
+ "type": "integer",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "nullable": true,
+ "example": 5
+ },
+ "bookmarkGroup": {
+ "oneOf": [
+ {
+ "type": "string",
+ "example": "verses_6236"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "verses_6236"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ }
+ ]
+ },
+ "isInDefaultCollection": {
+ "type": "boolean",
+ "example": true
+ },
+ "isReading": {
+ "type": "boolean",
+ "nullable": true,
+ "example": false
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "bookmarkType",
+ "key",
+ "bookmarkGroup",
+ "isInDefaultCollection",
+ "isReading"
+ ]
+ },
+ "Bookmark": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wqim00057z3fe30y0b3e"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "type": {
+ "type": "string",
+ "example": "ayah"
+ },
+ "key": {
+ "type": "integer",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "nullable": true,
+ "example": 5
+ },
+ "group": {
+ "type": "string",
+ "example": "verses_6236"
+ },
+ "isInDefaultCollection": {
+ "type": "boolean",
+ "example": true
+ },
+ "isReading": {
+ "type": "boolean",
+ "nullable": true,
+ "example": false
+ },
+ "collectionsCount": {
+ "type": "integer",
+ "description": "Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.",
+ "example": 1
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "type",
+ "key",
+ "group",
+ "isInDefaultCollection",
+ "isReading"
+ ],
+ "additionalProperties": false
+ },
+ "BookmarkWithCollectionsCount": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wqim00057z3fe30y0b3e"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "type": {
+ "type": "string",
+ "example": "ayah"
+ },
+ "key": {
+ "type": "integer",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "nullable": true,
+ "example": 5
+ },
+ "group": {
+ "type": "string",
+ "example": "verses_6236"
+ },
+ "isInDefaultCollection": {
+ "type": "boolean",
+ "example": true
+ },
+ "isReading": {
+ "type": "boolean",
+ "nullable": true,
+ "example": false
+ },
+ "collectionsCount": {
+ "type": "integer",
+ "description": "Total user-visible collection memberships for this bookmark, including Favorites when `isInDefaultCollection=true`.",
+ "example": 1
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "type",
+ "key",
+ "group",
+ "isInDefaultCollection",
+ "isReading",
+ "collectionsCount"
+ ],
+ "additionalProperties": false
+ },
+ "Collection": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wqsk00087z3f5hp42h08"
+ },
+ "name": {
+ "type": "string",
+ "example": "Woman in Quran"
+ },
+ "slug": {
+ "type": "string",
+ "nullable": true,
+ "example": "woman-in-quran"
+ },
+ "isPrivate": {
+ "type": "boolean",
+ "example": false
+ },
+ "isDefault": {
+ "type": "boolean",
+ "example": false
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true,
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "url": {
+ "type": "string",
+ "nullable": true,
+ "example": "cmnkcpmvc000814v9f5jtbsxf"
+ },
+ "bookmarksCount": {
+ "type": "integer",
+ "example": 1
+ },
+ "resourcesCount": {
+ "type": "integer",
+ "example": 1
+ },
+ "count": {
+ "type": "integer",
+ "example": 1
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "slug",
+ "isPrivate",
+ "isDefault",
+ "updatedAt"
+ ],
+ "additionalProperties": false
+ },
+ "EstimatedGoalTimelineDay": {
+ "type": "object",
+ "properties": {
+ "date": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The date of the estimated day",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "amount": {
+ "oneOf": [
+ {
+ "type": "string",
+ "example": "1:5-1:10"
+ },
+ {
+ "type": "integer",
+ "minimum": 1,
+ "example": 600
+ }
+ ],
+ "description": "The amount of the day's goal."
+ }
+ },
+ "required": [
+ "date",
+ "amount"
+ ],
+ "additionalProperties": false
+ },
+ "EstimatedGoalTimeline": {
+ "type": "object",
+ "properties": {
+ "week": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/EstimatedGoalTimelineDay"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "Preference": {
+ "type": "object",
+ "properties": {
+ "theme": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "light",
+ "sepia",
+ "dark"
+ ],
+ "example": "auto"
+ }
+ },
+ "additionalProperties": false
+ },
+ "reading": {
+ "type": "object",
+ "properties": {
+ "readingPreference": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "reading",
+ "readingTranslation"
+ ],
+ "example": "translation"
+ },
+ "selectedWordByWordLocale": {
+ "type": "string",
+ "enum": [
+ "en",
+ "ur",
+ "id",
+ "bn",
+ "tr",
+ "fa",
+ "ru",
+ "hi",
+ "de",
+ "ta",
+ "inh",
+ "fr",
+ "sq",
+ "dv",
+ "zh",
+ "sd",
+ "ml"
+ ],
+ "example": "en"
+ },
+ "wordClickFunctionality": {
+ "type": "string",
+ "enum": [
+ "play-audio",
+ "no-audio"
+ ],
+ "example": "play-audio"
+ },
+ "isReadingByRevelationOrder": {
+ "type": "boolean",
+ "example": true
+ },
+ "wordByWordContentType": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "transliteration"
+ ]
+ },
+ "example": [
+ "translation"
+ ]
+ },
+ "wordByWordDisplay": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "tooltip",
+ "inline"
+ ]
+ },
+ "example": [
+ "tooltip"
+ ]
+ },
+ "wordByWordTooltipContentType": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "transliteration"
+ ]
+ },
+ "example": [
+ "translation"
+ ]
+ },
+ "wordByWordInlineContentType": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "transliteration"
+ ]
+ },
+ "example": []
+ },
+ "selectedReadingTranslation": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "example": "131"
+ },
+ "selectedReflectionLanguages": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "minItems": 1
+ },
+ "selectedLessonLanguages": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "minItems": 1
+ }
+ },
+ "required": [
+ "readingPreference",
+ "selectedWordByWordLocale",
+ "wordClickFunctionality",
+ "selectedReadingTranslation"
+ ],
+ "additionalProperties": false
+ },
+ "quranReaderStyles": {
+ "type": "object",
+ "properties": {
+ "tafsirFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "quranTextFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "translationFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "wordByWordFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 6,
+ "example": 3
+ },
+ "reflectionFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "qnaFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "lessonFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "surahInfoFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "hadithFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "layersFontScale": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ },
+ "quranFont": {
+ "type": "string",
+ "enum": [
+ "code_v1",
+ "code_v2",
+ "text_uthmani",
+ "text_indopak",
+ "qpc_uthmani_hafs",
+ "tajweed",
+ "tajweed_v4"
+ ],
+ "example": "code_v1"
+ },
+ "mushafLines": {
+ "type": "string",
+ "enum": [
+ "15_lines",
+ "16_lines"
+ ],
+ "example": "16_lines"
+ },
+ "showTajweedRules": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "required": [
+ "tafsirFontScale",
+ "quranTextFontScale",
+ "translationFontScale",
+ "wordByWordFontScale",
+ "reflectionFontScale",
+ "qnaFontScale",
+ "lessonFontScale",
+ "surahInfoFontScale",
+ "hadithFontScale",
+ "layersFontScale"
+ ],
+ "additionalProperties": false
+ },
+ "translations": {
+ "type": "object",
+ "properties": {
+ "selectedTranslations": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "example": 131
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "tafsirs": {
+ "type": "object",
+ "properties": {
+ "selectedTafsirs": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "example": "en-tafisr-ibn-kathir"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "audio": {
+ "type": "object",
+ "properties": {
+ "reciter": {
+ "type": "integer",
+ "example": 7
+ },
+ "playbackRate": {
+ "type": "integer",
+ "enum": [
+ 0.25,
+ 0.5,
+ 0.75,
+ 1,
+ 1.25,
+ 1.5,
+ 1.75,
+ 2
+ ],
+ "example": 1
+ },
+ "showTooltipWhenPlayingAudio": {
+ "type": "boolean",
+ "example": true
+ },
+ "enableAutoScrolling": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "required": [
+ "reciter"
+ ],
+ "additionalProperties": false
+ },
+ "language": {
+ "type": "object",
+ "properties": {
+ "language": {
+ "type": "string",
+ "enum": [
+ "en",
+ "ar",
+ "bn",
+ "fa",
+ "fr",
+ "id",
+ "it",
+ "nl",
+ "pt",
+ "ru",
+ "sq",
+ "th",
+ "tr",
+ "ur",
+ "zh",
+ "ms",
+ "es",
+ "sw",
+ "vi"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "userHasCustomised": {
+ "type": "object",
+ "properties": {
+ "userHasCustomised": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "required": [
+ "userHasCustomised"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "ReadingSession": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "cmoa3wrpk000h7z3f2t6a57dg"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "chapterNumber": {
+ "type": "integer",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "example": 5
+ }
+ },
+ "required": [
+ "id",
+ "updatedAt"
+ ],
+ "additionalProperties": false
+ },
+ "UserProfile": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "example": "2022-12-06T06:16:20.229Z"
+ },
+ "email": {
+ "type": "string",
+ "example": "muhajir@quran.com"
+ },
+ "firstName": {
+ "type": "string",
+ "example": "Muhammad"
+ },
+ "lastName": {
+ "type": "string",
+ "example": "Muhajir"
+ },
+ "photoUrl": {
+ "type": "string",
+ "example": "https://photos.quran.com/img/muhajir.jpg"
+ }
+ },
+ "additionalProperties": false
+ },
+ "EditProfileDto": {
+ "type": "object",
+ "properties": {
+ "languageId": {
+ "type": "number"
+ },
+ "reflectionLanguages": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "ayahLanguages": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "customized": {
+ "type": "boolean"
+ },
+ "hideFollowSuggestion": {
+ "type": "boolean",
+ "description": "Hide follow suggestion popup after liking a post"
+ },
+ "showFollowFeaturedSuggestion": {
+ "type": "boolean",
+ "description": "Show featured follow suggestion popup on QR onboarding"
+ }
+ }
+ },
+ "UserSerializedDto": {
+ "type": "object",
+ "properties": {
+ "avatarUrls": {
+ "type": "object",
+ "example": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ }
+ },
+ "createdAt": {
+ "type": "object",
+ "example": "2000-01-21 00:00:00"
+ },
+ "joiningYear": {
+ "type": "number",
+ "example": 2025
+ },
+ "isPasswordSet": {
+ "type": "boolean",
+ "example": true
+ },
+ "settings": {
+ "type": "object",
+ "properties": {
+ "ayahLanguages": {
+ "required": false,
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ },
+ "reflectionLanguages": {
+ "required": false,
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ "username": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "postAs": {
+ "type": "boolean",
+ "default": false
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "postsCount": {
+ "type": "number",
+ "default": 0
+ },
+ "averageToxicity": {
+ "type": "number",
+ "default": 0
+ },
+ "languageId": {
+ "type": "number"
+ },
+ "banned": {
+ "type": "boolean",
+ "default": false
+ },
+ "memberType": {
+ "type": "number"
+ },
+ "followersCount": {
+ "type": "number",
+ "default": 0
+ },
+ "likesCount": {
+ "type": "number",
+ "default": 0
+ },
+ "isAdmin": {
+ "type": "boolean",
+ "default": false
+ },
+ "languageIsoCode": {
+ "type": "string",
+ "default": "en"
+ },
+ "bio": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "followed": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "avatarUrls",
+ "createdAt",
+ "joiningYear",
+ "settings",
+ "id"
+ ]
+ },
+ "UpdateProfileDto": {
+ "type": "object",
+ "properties": {
+ "avatar": {
+ "type": "string",
+ "pattern": "/^data:image\\/[a-z]+;base64,/"
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "bio": {
+ "type": "string",
+ "nullable": true
+ },
+ "country": {
+ "type": "string",
+ "nullable": true
+ },
+ "removeAvatar": {
+ "type": "boolean"
+ }
+ }
+ },
+ "UpdateProfileBodyDto": {
+ "type": "object",
+ "properties": {
+ "user": {
+ "$ref": "#/components/schemas/UpdateProfileDto"
+ }
+ },
+ "required": [
+ "user"
+ ]
+ },
+ "UserRoomDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ },
+ "group": {
+ "type": "string"
+ },
+ "public": {
+ "type": "boolean"
+ },
+ "roomType": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean"
+ },
+ "subdomain": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "membersCount": {
+ "type": "number"
+ },
+ "avatarUrl": {
+ "type": "object",
+ "properties": {
+ "small": {
+ "required": true,
+ "type": "string"
+ },
+ "medium": {
+ "required": true,
+ "type": "string"
+ },
+ "large": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "group",
+ "public",
+ "roomType",
+ "verified",
+ "subdomain",
+ "description",
+ "membersCount",
+ "avatarUrl"
+ ]
+ },
+ "UserRoomsResponse": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserRoomDto"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "UserSearchDto": {
+ "type": "object",
+ "properties": {
+ "avatarUrls": {
+ "type": "object",
+ "example": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ }
+ },
+ "createdAt": {
+ "type": "object",
+ "example": "2000-01-21 00:00:00"
+ },
+ "joiningYear": {
+ "type": "number",
+ "example": 2025
+ },
+ "isPasswordSet": {
+ "type": "boolean",
+ "example": true
+ },
+ "isFollowed": {
+ "type": "boolean",
+ "example": false
+ },
+ "followed": {
+ "type": "boolean",
+ "example": false
+ },
+ "settings": {
+ "type": "object",
+ "properties": {
+ "ayahLanguages": {
+ "required": false,
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ },
+ "reflectionLanguages": {
+ "required": false,
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ },
+ "username": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "postAs": {
+ "type": "boolean",
+ "default": false
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "postsCount": {
+ "type": "number",
+ "default": 0
+ },
+ "averageToxicity": {
+ "type": "number",
+ "default": 0
+ },
+ "languageId": {
+ "type": "number"
+ },
+ "banned": {
+ "type": "boolean",
+ "default": false
+ },
+ "memberType": {
+ "type": "number"
+ },
+ "followersCount": {
+ "type": "number",
+ "default": 0
+ },
+ "likesCount": {
+ "type": "number",
+ "default": 0
+ },
+ "isAdmin": {
+ "type": "boolean",
+ "default": false
+ },
+ "languageIsoCode": {
+ "type": "string",
+ "default": "en"
+ },
+ "bio": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "avatarUrls",
+ "createdAt",
+ "joiningYear",
+ "settings",
+ "id"
+ ]
+ },
+ "UsersSearchResponse": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserSearchDto"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "ToggleFollowDto": {
+ "type": "object",
+ "properties": {
+ "action": {
+ "enum": [
+ "follow",
+ "unfollow"
+ ],
+ "type": "string",
+ "description": "The intended action: follow or unfollow",
+ "example": "follow"
+ }
+ }
+ },
+ "FeaturedUserDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "1f8d6f3f-2f57-4c3e-b7b5-5f6a9d7f7a55"
+ },
+ "username": {
+ "type": "string",
+ "example": "example.user"
+ },
+ "verified": {
+ "type": "boolean",
+ "example": true
+ },
+ "firstName": {
+ "type": "string",
+ "example": "Example"
+ },
+ "lastName": {
+ "type": "string",
+ "example": "User"
+ },
+ "fullName": {
+ "type": "string",
+ "example": "Example User"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "example": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ }
+ },
+ "followersCount": {
+ "type": "number",
+ "example": 1200
+ },
+ "bio": {
+ "type": "string",
+ "example": "I write reflections on the Quran."
+ }
+ },
+ "required": [
+ "id",
+ "username",
+ "verified",
+ "firstName",
+ "lastName",
+ "fullName",
+ "avatarUrls",
+ "followersCount"
+ ]
+ },
+ "FeaturedUsersResponseDto": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FeaturedUserDto"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "FailedFeaturedFollowItemDto": {
+ "type": "object",
+ "properties": {
+ "followeeId": {
+ "type": "string",
+ "example": "user-id-123"
+ },
+ "reason": {
+ "type": "string",
+ "example": "FOLLOW_FAILED"
+ }
+ },
+ "required": [
+ "followeeId",
+ "reason"
+ ]
+ },
+ "FollowFeaturedUsersResponseDto": {
+ "type": "object",
+ "properties": {
+ "requested": {
+ "type": "number",
+ "example": 9
+ },
+ "followed": {
+ "type": "number",
+ "example": 7
+ },
+ "skipped": {
+ "type": "number",
+ "example": 1
+ },
+ "failed": {
+ "type": "number",
+ "example": 1
+ },
+ "complete": {
+ "type": "boolean",
+ "example": true
+ },
+ "failedItems": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/FailedFeaturedFollowItemDto"
+ }
+ }
+ },
+ "required": [
+ "requested",
+ "followed",
+ "skipped",
+ "failed",
+ "complete"
+ ]
+ },
+ "RoomAdminUpdateDto": {
+ "type": "object",
+ "properties": {
+ "roomId": {
+ "type": "number"
+ },
+ "userId": {
+ "type": "string"
+ },
+ "admin": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "roomId",
+ "userId",
+ "admin"
+ ]
+ },
+ "UpdateGroupDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 50
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 200
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 50
+ },
+ "removeAvatar": {
+ "type": "boolean"
+ },
+ "avatar": {
+ "type": "string",
+ "pattern": "/^data:image\\/[a-z]+;base64,/"
+ },
+ "country": {
+ "type": "string",
+ "nullable": true
+ },
+ "public": {
+ "type": "boolean",
+ "nullable": true,
+ "default": null
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "UpdatePageDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "removeAvatar": {
+ "type": "boolean"
+ },
+ "avatar": {
+ "type": "string",
+ "pattern": "/^data:image\\/[a-z]+;base64,/"
+ },
+ "public": {
+ "type": "boolean",
+ "nullable": true,
+ "default": null
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "organizationWebsite": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "MemberSerializedDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "example": "user-1"
+ },
+ "username": {
+ "type": "string",
+ "example": "member.username"
+ },
+ "firstName": {
+ "type": "string",
+ "example": "Member"
+ },
+ "lastName": {
+ "type": "string",
+ "example": "User"
+ },
+ "verified": {
+ "type": "boolean",
+ "example": true
+ },
+ "avatarUrls": {
+ "type": "object",
+ "example": {
+ "small": "https://avatars.quran.foundation/users/user-1/small.png",
+ "medium": "https://avatars.quran.foundation/users/user-1/medium.png",
+ "large": "https://avatars.quran.foundation/users/user-1/large.png"
+ }
+ },
+ "isAdmin": {
+ "type": "boolean",
+ "example": false
+ },
+ "isOwner": {
+ "type": "boolean",
+ "example": false
+ },
+ "isFollowed": {
+ "type": "boolean",
+ "example": true
+ },
+ "isActive": {
+ "type": "boolean",
+ "example": true
+ },
+ "followersCount": {
+ "type": "number",
+ "example": 42
+ }
+ },
+ "required": [
+ "id",
+ "username",
+ "firstName",
+ "lastName",
+ "verified",
+ "avatarUrls",
+ "isAdmin",
+ "isOwner",
+ "isFollowed",
+ "isActive",
+ "followersCount"
+ ]
+ },
+ "RoomMembersResponseDto": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/MemberSerializedDto"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "InviteUserDto": {
+ "type": "object",
+ "properties": {
+ "userIds": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "emails": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "required": [
+ "userIds",
+ "emails"
+ ]
+ },
+ "RoomInviteUserResponseDto": {
+ "type": "object",
+ "properties": {
+ "invited": {
+ "type": "boolean",
+ "example": true
+ },
+ "inviteStatus": {
+ "type": "object",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "boolean"
+ },
+ {
+ "type": "string"
+ }
+ ]
+ },
+ "example": {
+ "user-123": true,
+ "user-456": "already_a_member"
+ }
+ }
+ },
+ "required": [
+ "invited",
+ "inviteStatus"
+ ]
+ },
+ "RoomInviteAcceptedResponseDto": {
+ "type": "object",
+ "properties": {
+ "accepted": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "required": [
+ "accepted"
+ ]
+ },
+ "RoomInviteRejectedResponseDto": {
+ "type": "object",
+ "properties": {
+ "rejected": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "required": [
+ "rejected"
+ ]
+ },
+ "CreatePageDto": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "jobTitle": {
+ "type": "string"
+ },
+ "contactNumber": {
+ "type": "string"
+ },
+ "organizationName": {
+ "type": "string"
+ },
+ "organizationWebsite": {
+ "type": "string"
+ },
+ "purpose": {
+ "type": "string"
+ },
+ "additionalDetails": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ },
+ "url": {
+ "type": "string"
+ },
+ "public": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "jobTitle",
+ "contactNumber",
+ "organizationName",
+ "purpose",
+ "url"
+ ]
+ },
+ "CreateGroupDto": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 50
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 200
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 50
+ },
+ "public": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "name",
+ "url"
+ ]
+ },
+ "RoomListItemDto": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "roomType": {
+ "type": "string"
+ },
+ "isActive": {
+ "type": "boolean"
+ },
+ "isVerified": {
+ "type": "boolean"
+ },
+ "isPublic": {
+ "type": "boolean"
+ },
+ "isOwner": {
+ "type": "boolean"
+ },
+ "isAdmin": {
+ "type": "boolean"
+ },
+ "ownerId": {
+ "type": "string"
+ },
+ "postsCount": {
+ "type": "number"
+ },
+ "membersCount": {
+ "type": "number"
+ },
+ "url": {
+ "type": "string"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "properties": {
+ "thumb": {
+ "required": true,
+ "type": "string"
+ },
+ "original": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "isMember": {
+ "type": "boolean"
+ },
+ "subdomain": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "description",
+ "roomType",
+ "isActive",
+ "isVerified",
+ "isPublic",
+ "isOwner",
+ "isAdmin",
+ "ownerId",
+ "postsCount",
+ "membersCount",
+ "avatarUrls"
+ ]
+ },
+ "RoomCreatedResponseDto": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/RoomListItemDto"
+ }
+ },
+ "required": [
+ "success",
+ "data"
+ ]
+ },
+ "PaginatedRoomsResponseDto": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/RoomListItemDto"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "RoomProfileResponseDto": {
+ "type": "object",
+ "properties": {
+ "privateToken": {
+ "type": "string",
+ "example": "private-room-token"
+ },
+ "mutualFollowers": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserSerializedDto"
+ }
+ },
+ "mutualFollowersCount": {
+ "type": "number",
+ "example": 2
+ },
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "roomType": {
+ "type": "string"
+ },
+ "isActive": {
+ "type": "boolean"
+ },
+ "isVerified": {
+ "type": "boolean"
+ },
+ "isPublic": {
+ "type": "boolean"
+ },
+ "isOwner": {
+ "type": "boolean"
+ },
+ "isAdmin": {
+ "type": "boolean"
+ },
+ "ownerId": {
+ "type": "string"
+ },
+ "postsCount": {
+ "type": "number"
+ },
+ "membersCount": {
+ "type": "number"
+ },
+ "url": {
+ "type": "string"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "properties": {
+ "thumb": {
+ "required": true,
+ "type": "string"
+ },
+ "original": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "isMember": {
+ "type": "boolean"
+ },
+ "subdomain": {
+ "type": "string"
+ },
+ "country": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "name",
+ "description",
+ "roomType",
+ "isActive",
+ "isVerified",
+ "isPublic",
+ "isOwner",
+ "isAdmin",
+ "ownerId",
+ "postsCount",
+ "membersCount",
+ "avatarUrls"
+ ]
+ },
+ "RoomAcceptByPrivateTokenResponseDto": {
+ "type": "object",
+ "properties": {
+ "roomId": {
+ "type": "number",
+ "example": 42
+ },
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "isNewMember": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "required": [
+ "roomId",
+ "success",
+ "isNewMember"
+ ]
+ },
+ "PostTag": {
+ "type": "object",
+ "properties": {
+ "language": {
+ "type": "string"
+ },
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "PostReference": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "from": {
+ "type": "number"
+ },
+ "to": {
+ "type": "number"
+ },
+ "chapterId": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "UserAuthor": {
+ "type": "object",
+ "properties": {
+ "postsCount": {
+ "type": "number"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "properties": {
+ "small": {
+ "required": true,
+ "type": "string"
+ },
+ "medium": {
+ "required": true,
+ "type": "string"
+ },
+ "large": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
+ "id": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "memberType": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "avatarUrls",
+ "id"
+ ]
+ },
+ "PostRecentComment": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "author": {
+ "$ref": "#/components/schemas/UserAuthor"
+ },
+ "body": {
+ "type": "string"
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "author",
+ "body",
+ "createdAt"
+ ]
+ },
+ "PostRoom": {
+ "type": "object",
+ "properties": {
+ "isAdmin": {
+ "type": "object"
+ },
+ "isOwner": {
+ "type": "object"
+ },
+ "isPublic": {
+ "type": "object"
+ },
+ "id": {
+ "type": "number"
+ },
+ "subdomain": {
+ "type": "string"
+ },
+ "roomType": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "name": {
+ "type": "string"
+ },
+ "_group": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "UserWithMentionLocations": {
+ "type": "object",
+ "properties": {
+ "postsCount": {
+ "type": "number"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "properties": {
+ "small": {
+ "required": true,
+ "type": "string"
+ },
+ "medium": {
+ "required": true,
+ "type": "string"
+ },
+ "large": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
+ "id": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "memberType": {
+ "type": "number"
+ },
+ "locations": {
+ "type": "object"
+ },
+ "followersCount": {
+ "type": "number"
+ },
+ "displayName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "avatarUrls",
+ "id",
+ "locations",
+ "followersCount"
+ ]
+ },
+ "PostSerialized": {
+ "type": "object",
+ "properties": {
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PostTag"
+ }
+ },
+ "references": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PostReference"
+ }
+ },
+ "author": {
+ "type": "object"
+ },
+ "recentComment": {
+ "$ref": "#/components/schemas/PostRecentComment"
+ },
+ "room": {
+ "nullable": true,
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/PostRoom"
+ }
+ ]
+ },
+ "mentions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserWithMentionLocations"
+ }
+ },
+ "isLiked": {
+ "type": "boolean"
+ },
+ "isByFollowedUser": {
+ "type": "boolean"
+ },
+ "isCommentedOn": {
+ "type": "boolean"
+ },
+ "isSaved": {
+ "type": "boolean"
+ },
+ "id": {
+ "type": "number"
+ },
+ "authorId": {
+ "type": "string"
+ },
+ "body": {
+ "type": "string"
+ },
+ "discussionId": {
+ "type": "number"
+ },
+ "draft": {
+ "type": "boolean",
+ "default": false
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "updatedAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "publishedAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "global": {
+ "type": "boolean"
+ },
+ "toxicityScore": {
+ "type": "number"
+ },
+ "reported": {
+ "type": "boolean",
+ "default": false
+ },
+ "views": {
+ "type": "number"
+ },
+ "removed": {
+ "type": "boolean",
+ "default": false
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "roomPostStatus": {
+ "description": "@description 0: OnlyMembers, 1: Publicly, 2: AsRoom",
+ "default": 0,
+ "enum": [
+ 0,
+ 1,
+ 2
+ ],
+ "type": "number"
+ },
+ "hidden": {
+ "type": "boolean",
+ "default": false
+ },
+ "commentsCount": {
+ "type": "number",
+ "default": 0
+ },
+ "likesCount": {
+ "type": "number",
+ "default": 0
+ },
+ "viewsCount": {
+ "type": "number",
+ "default": 0
+ },
+ "languageId": {
+ "type": "number"
+ },
+ "languageName": {
+ "type": "string"
+ },
+ "moderationStatus": {
+ "description": "featured = 1, // Like Sticky posts, will be featured for a time period.Shown at top in feed and partner apps\n\npromoted = 2, // High quality content.Shown at top(after featured) in feed and partner apps\n\nnormal = 3, // Default status, available in search, latest and popular tabs.In feed(if you're following the author)\n\nhidden = 4, // Visible only to author or moderators, or via private share link.\n\nprivate_note = 5, // Private notes, only visible to author or via private share link.These are the posts made \"private\" by moderators.\n\nrequested_review = 6, // User requested the review, treat them has hidden.Only visible to author and moderators\n\ndeleted = 30,",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 30
+ ],
+ "type": "number"
+ },
+ "reviewedAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "featuredAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "estimatedReadingTime": {
+ "type": "number",
+ "default": 0
+ },
+ "roomId": {
+ "type": "number"
+ },
+ "postTypeId": {
+ "type": "number"
+ },
+ "postTypeName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "id",
+ "authorId",
+ "createdAt",
+ "updatedAt",
+ "commentsCount",
+ "roomId",
+ "postTypeId"
+ ]
+ },
+ "FeedResponseDto": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/PostSerialized"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "data"
+ ]
+ },
+ "RoomPostUpdatePrivacyDto": {
+ "type": "object",
+ "properties": {
+ "isPublic": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "isPublic"
+ ]
+ },
+ "ReferenceAttributes": {
+ "type": "object",
+ "properties": {
+ "chapterId": {
+ "type": "number",
+ "minimum": 1
+ },
+ "from": {
+ "type": "number",
+ "default": 0
+ },
+ "to": {
+ "type": "number",
+ "default": 0
+ }
+ },
+ "required": [
+ "chapterId",
+ "from",
+ "to"
+ ]
+ },
+ "UserMentionAttributes": {
+ "type": "object",
+ "properties": {
+ "marker": {
+ "type": "string",
+ "pattern": "/{{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}}}/",
+ "example": "{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}"
+ },
+ "userId": {
+ "type": "string"
+ },
+ "displayName": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "marker",
+ "userId",
+ "displayName"
+ ]
+ },
+ "CreatePostDto": {
+ "type": "object",
+ "properties": {
+ "roomPostStatus": {
+ "enum": [
+ 0,
+ 1,
+ 2
+ ],
+ "type": "number",
+ "description": "The room post status, defaults to publicly: 1. As Room: 0, Publicly: 1, Only Members: 2"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6
+ },
+ "draft": {
+ "type": "boolean"
+ },
+ "references": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ReferenceAttributes"
+ }
+ },
+ "mentions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserMentionAttributes"
+ }
+ },
+ "roomId": {
+ "type": "number"
+ },
+ "postAsAuthorId": {
+ "type": "string"
+ },
+ "publishedAt": {
+ "format": "date-time",
+ "type": "string"
+ }
+ },
+ "required": [
+ "roomPostStatus",
+ "body",
+ "draft",
+ "references",
+ "mentions",
+ "roomId",
+ "postAsAuthorId",
+ "publishedAt"
+ ]
+ },
+ "CreatePostBodyDto": {
+ "type": "object",
+ "properties": {
+ "post": {
+ "$ref": "#/components/schemas/CreatePostDto"
+ }
+ },
+ "required": [
+ "post"
+ ]
+ },
+ "PostCreatedResponse": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/PostSerialized"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "data",
+ "success"
+ ]
+ },
+ "UpdatePostDto": {
+ "type": "object",
+ "properties": {
+ "roomPostStatus": {
+ "enum": [
+ 0,
+ 1,
+ 2
+ ],
+ "type": "number",
+ "description": "The room post status, defaults to publicly: 1. As Room: 0, Publicly: 1, Only Members: 2"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6
+ },
+ "draft": {
+ "type": "boolean"
+ },
+ "references": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ReferenceAttributes"
+ }
+ },
+ "mentions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserMentionAttributes"
+ }
+ },
+ "roomId": {
+ "type": "number"
+ },
+ "postAsAuthorId": {
+ "type": "string"
+ },
+ "publishedAt": {
+ "format": "date-time",
+ "type": "string"
+ }
+ }
+ },
+ "ReportAbuseDto": {
+ "type": "object",
+ "properties": {
+ "abuse": {
+ "type": "string"
+ },
+ "comments": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ "required": [
+ "abuse",
+ "comments"
+ ]
+ },
+ "ReportAbuseBodyDto": {
+ "type": "object",
+ "properties": {
+ "report": {
+ "$ref": "#/components/schemas/ReportAbuseDto"
+ }
+ },
+ "required": [
+ "report"
+ ]
+ },
+ "CommentAuthor": {
+ "type": "object",
+ "properties": {
+ "postsCount": {
+ "type": "number"
+ },
+ "avatarUrls": {
+ "type": "object",
+ "properties": {
+ "small": {
+ "required": true,
+ "type": "string"
+ },
+ "medium": {
+ "required": true,
+ "type": "string"
+ },
+ "large": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
+ "id": {
+ "type": "string"
+ },
+ "username": {
+ "type": "string"
+ },
+ "verified": {
+ "type": "boolean",
+ "default": false
+ },
+ "firstName": {
+ "type": "string"
+ },
+ "lastName": {
+ "type": "string"
+ },
+ "memberType": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "avatarUrls",
+ "id"
+ ]
+ },
+ "CommentTag": {
+ "type": "object",
+ "properties": {
+ "language": {
+ "type": "string"
+ },
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ },
+ "commentsCount": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id"
+ ]
+ },
+ "Comment": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "postId": {
+ "type": "number"
+ },
+ "authorId": {
+ "type": "string"
+ },
+ "parentId": {
+ "type": "number"
+ },
+ "isPrivate": {
+ "type": "boolean",
+ "default": false
+ },
+ "body": {
+ "type": "string"
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "updatedAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "toxicityScore": {
+ "type": "number"
+ },
+ "repliesCount": {
+ "type": "number",
+ "default": 0
+ },
+ "likesCount": {
+ "type": "number",
+ "default": 0
+ },
+ "reported": {
+ "type": "boolean",
+ "default": false
+ },
+ "removed": {
+ "type": "boolean",
+ "default": false
+ },
+ "hidden": {
+ "type": "boolean",
+ "default": false
+ },
+ "languageId": {
+ "type": "number"
+ },
+ "languageName": {
+ "type": "string"
+ },
+ "moderationStatus": {
+ "type": "number"
+ },
+ "author": {
+ "$ref": "#/components/schemas/CommentAuthor"
+ },
+ "mentions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserWithMentionLocations"
+ }
+ },
+ "tags": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/CommentTag"
+ }
+ }
+ },
+ "required": [
+ "id",
+ "postId",
+ "authorId",
+ "parentId",
+ "isPrivate",
+ "body",
+ "createdAt",
+ "updatedAt"
+ ]
+ },
+ "PostCommentsResponse": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "comments": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Comment"
+ }
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "comments"
+ ]
+ },
+ "PostAllCommentsResponse": {
+ "type": "object",
+ "properties": {
+ "comments": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Comment"
+ }
+ },
+ "total": {
+ "type": "number",
+ "example": "10 // works also with swagger setup"
+ }
+ },
+ "required": [
+ "comments",
+ "total"
+ ]
+ },
+ "ExportPostsDto": {
+ "type": "object",
+ "properties": {
+ "ids": {
+ "description": "Array of post IDs to export",
+ "example": [
+ 1,
+ 2,
+ 3
+ ],
+ "minItems": 1,
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ },
+ "required": [
+ "ids"
+ ]
+ },
+ "Tag": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "number"
+ },
+ "name": {
+ "type": "string"
+ },
+ "createdAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "updatedAt": {
+ "format": "date-time",
+ "type": "string"
+ },
+ "rank": {
+ "type": "number",
+ "default": 0
+ },
+ "languageId": {
+ "type": "number"
+ },
+ "languageName": {
+ "type": "string"
+ },
+ "postsCount": {
+ "type": "number"
+ },
+ "commentsCount": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt"
+ ]
+ },
+ "CreateCommentDto": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "description": "Comment body text",
+ "example": "This is a thoughtful comment about the post",
+ "maxLength": 8000
+ },
+ "postId": {
+ "type": "number",
+ "description": "ID of the post this comment belongs to",
+ "example": 123
+ },
+ "isPrivate": {
+ "type": "boolean",
+ "default": false,
+ "description": "Whether the comment is private",
+ "example": false
+ },
+ "parentId": {
+ "type": "number",
+ "description": "ID of the parent comment (for replies)",
+ "example": 456
+ },
+ "mentions": {
+ "description": "User mentions in the comment",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/UserMentionAttributes"
+ }
+ }
+ },
+ "required": [
+ "body",
+ "postId",
+ "isPrivate"
+ ]
+ },
+ "CreateCommentBody": {
+ "type": "object",
+ "properties": {
+ "comment": {
+ "description": "Comment details for creation",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/CreateCommentDto"
+ }
+ ]
+ }
+ },
+ "required": [
+ "comment"
+ ]
+ },
+ "CreateCommentResponse": {
+ "type": "object",
+ "properties": {
+ "comment": {
+ "$ref": "#/components/schemas/Comment"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "comment",
+ "success"
+ ]
+ },
+ "CommentRepliesResponse": {
+ "type": "object",
+ "properties": {
+ "total": {
+ "type": "number",
+ "example": 10
+ },
+ "currentPage": {
+ "type": "number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "example": 10
+ },
+ "pages": {
+ "type": "number",
+ "example": 1
+ },
+ "replies": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Comment"
+ }
+ },
+ "comment": {
+ "$ref": "#/components/schemas/Comment"
+ }
+ },
+ "required": [
+ "total",
+ "currentPage",
+ "limit",
+ "pages",
+ "replies",
+ "comment"
+ ]
+ }
+ },
+ "responses": {}
+ },
+ "security": [
+ {
+ "x-auth-token": [],
+ "x-client-id": []
+ }
+ ],
+ "paths": {
+ "/v1/collections": {
+ "post": {
+ "description": "Create a new collection under user's account.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Add collection",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the new collection to be created.",
+ "example": "Woman in Quran"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "name": "Woman in Quran"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/Collection"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "cmoa3wqsk00087z3f5hp42h08",
+ "name": "Woman in Quran",
+ "slug": "woman-in-quran",
+ "isPrivate": false,
+ "isDefault": false,
+ "updatedAt": "2023-01-21T07:28:13.023Z",
+ "url": "cmnkcpmvc000814v9f5jtbsxf",
+ "bookmarksCount": 1,
+ "resourcesCount": 1,
+ "count": 1
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1Collections"
+ },
+ "get": {
+ "tags": [
+ "Collections"
+ ],
+ "description": "List collections owned by the user. This api contains pagination. Read more about [pagination](/docs/user_related_apis_versioned/user-related-apis#pagination)",
+ "summary": "Get all collections",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "sortBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "recentlyUpdated",
+ "alphabetical"
+ ],
+ "description": "Sort the collections list either by the time they were updated at descendingly or alphabetically.",
+ "example": "recentlyUpdated"
+ },
+ "description": "Sort the collections list either by the time they were updated at descendingly or alphabetically."
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "page",
+ "juz",
+ "surah",
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "description": "The bookmark type."
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Collection"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wqsk00087z3f5hp42h08",
+ "name": "Woman in Quran",
+ "slug": "woman-in-quran",
+ "isPrivate": false,
+ "isDefault": false,
+ "updatedAt": "2023-01-21T07:28:13.023Z",
+ "url": "cmnkcpmvc000814v9f5jtbsxf",
+ "bookmarksCount": 1,
+ "resourcesCount": 1,
+ "count": 1
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1Collections"
+ }
+ },
+ "/v1/collections/{collectionId}/bookmarks": {
+ "post": {
+ "description": "Add a bookmark to a collection. Use `collectionId=\"__default__\"` to add an ayah bookmark to the virtual Favorites collection used by Quran.com.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Add collection Bookmark",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "The collection ID. Use `__default__` to add an ayah bookmark to the virtual Favorites collection used by Quran.com.",
+ "example": "cmoa3wqvw00097z3f9tk87gga"
+ },
+ "required": true,
+ "description": "The collection ID. Use `__default__` to add an ayah bookmark to the virtual Favorites collection used by Quran.com."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "The Surah number.",
+ "example": 2
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "verseNumber": {
+ "type": "integer",
+ "example": 3
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key",
+ "verseNumber"
+ ],
+ "additionalProperties": false,
+ "title": "Ayah"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "Surah, Juz or page number."
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "juz",
+ "page",
+ "surah"
+ ],
+ "description": "The bookmark type.",
+ "example": "surah"
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key"
+ ],
+ "additionalProperties": false,
+ "title": "Surah, Juz, Or Page"
+ }
+ ]
+ },
+ "example": {
+ "key": 2,
+ "type": "ayah",
+ "verseNumber": 3,
+ "mushafId": 4,
+ "mushaf": 4
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "collection bookmark added"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "collection bookmark added"
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1CollectionsByCollectionIdBookmarks"
+ },
+ "delete": {
+ "description": "Delete a bookmark from a collection by bookmark details. Use `collectionId=\"__default__\"` to remove a bookmark from the virtual Favorites collection. When successfully deleted, the bookmark itself is only detached from the collection unless it becomes an orphan.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Delete collection bookmark by details",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection.",
+ "example": "cmoa3wr2h000f7z3ffr5fc0z1"
+ },
+ "required": true,
+ "description": "The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {}
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "Surah number",
+ "example": 2
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "verseNumber": {
+ "type": "integer",
+ "example": 3
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key",
+ "verseNumber"
+ ],
+ "additionalProperties": false,
+ "title": "Ayah"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "Surah, Juz or page number."
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "juz",
+ "page",
+ "surah"
+ ],
+ "description": "The bookmark type.",
+ "example": "surah"
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key"
+ ],
+ "additionalProperties": false,
+ "title": "Surah, Juz, Or Page"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "bookmarkId": {
+ "type": "string",
+ "description": "The Id of the bookmark to be deleted.",
+ "example": "cmoa3wr2h000e7z3fcxefa6rx"
+ }
+ },
+ "required": [
+ "bookmarkId"
+ ],
+ "additionalProperties": false,
+ "title": "Bookmark ID"
+ }
+ ],
+ "title": "input"
+ },
+ "example": {
+ "key": 2,
+ "type": "ayah",
+ "verseNumber": 3,
+ "mushafId": 4,
+ "mushaf": 4
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1CollectionsByCollectionIdBookmarks"
+ }
+ },
+ "/v1/collections/{collectionId}": {
+ "delete": {
+ "description": "Delete a an existing collection.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Delete collection",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "The Id of the collection to be deleted.",
+ "example": "cmoa3wqwh000a7z3f0d6y5mte"
+ },
+ "required": true,
+ "description": "The Id of the collection to be deleted."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "collection deleted"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "collection deleted"
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1CollectionsByCollectionId"
+ },
+ "get": {
+ "description": "Get all resources that belong to an existing collection by collection id. Use `__default__` to fetch the virtual Favorites collection.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Get collection items by id",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "Collection ID. Use `__default__` for the virtual Favorites collection.",
+ "example": "cmoa3wr17000d7z3f7ssph68y"
+ },
+ "description": "Collection ID. Use `__default__` for the virtual Favorites collection."
+ },
+ {
+ "in": "query",
+ "name": "sortBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "recentlyAdded",
+ "verseKey"
+ ],
+ "description": "Sort the collection items either by the time they were added at descendingly or by Ayah key."
+ },
+ "description": "Sort the collection items either by the time they were added at descendingly or by Ayah key."
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "collection": {
+ "$ref": "#/components/schemas/Collection"
+ },
+ "bookmarks": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/BookmarkWithCollectionsCount"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "collection": {
+ "id": "cmoa3wqsk00087z3f5hp42h08",
+ "name": "Woman in Quran",
+ "slug": "woman-in-quran",
+ "isPrivate": false,
+ "isDefault": false,
+ "updatedAt": "2023-01-21T07:28:13.023Z",
+ "url": "cmnkcpmvc000814v9f5jtbsxf",
+ "bookmarksCount": 1,
+ "resourcesCount": 1,
+ "count": 1
+ },
+ "bookmarks": [
+ {
+ "id": "cmoa3wqim00057z3fe30y0b3e",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "type": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "group": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false,
+ "collectionsCount": 1
+ }
+ ]
+ },
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1CollectionsByCollectionId"
+ },
+ "post": {
+ "description": "Update an existing collection.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Update collection",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "The Id of the collection to be updated."
+ },
+ "required": true,
+ "description": "The Id of the collection to be updated."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The new name of the collection to be updated."
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "name": "string"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "collection renamed"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "collection renamed"
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1CollectionsByCollectionId"
+ }
+ },
+ "/v1/collections/{collectionId}/bookmarks/{bookmarkId}": {
+ "delete": {
+ "description": "Delete a bookmark from a collection by bookmark ID. Use `collectionId=\"__default__\"` to remove a bookmark from the virtual Favorites collection. When successfully deleted, the bookmark itself is only detached from the collection unless it becomes an orphan.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Delete collection bookmark by id",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "collectionId",
+ "schema": {
+ "type": "string",
+ "description": "The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection.",
+ "example": "cmoa3wqxe000b7z3f6d6ia4ih"
+ },
+ "required": true,
+ "description": "The collection ID. Use `__default__` to remove a bookmark from the virtual Favorites collection."
+ },
+ {
+ "in": "path",
+ "name": "bookmarkId",
+ "schema": {
+ "type": "string",
+ "description": "The Id of the bookmark to be deleted.",
+ "example": "cmoa3wqxe000c7z3f61siesdm"
+ },
+ "required": true,
+ "description": "The Id of the bookmark to be deleted."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "collection bookmark deleted"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "collection bookmark deleted"
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1CollectionsByCollectionIdBookmarksByBookmarkId"
+ }
+ },
+ "/v1/collections/all": {
+ "get": {
+ "description": "Get all existing collections along with resources that belong to them.",
+ "tags": [
+ "Collections"
+ ],
+ "summary": "Get all collection items",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "sortBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "recentlyAdded",
+ "verseKey"
+ ],
+ "description": "Sort the collection items either by the time they were added at descendingly or alphabetically."
+ },
+ "description": "Sort the collection items either by the time they were added at descendingly or alphabetically."
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "page",
+ "juz",
+ "surah",
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "description": "The bookmark type."
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Bookmark"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wqim00057z3fe30y0b3e",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "type": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "group": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false,
+ "collectionsCount": 1
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1CollectionsAll"
+ }
+ },
+ "/v1/bookmarks": {
+ "post": {
+ "description": "Add or update a bookmark by details. Omit `isReading` to create or update a regular standalone bookmark. Set `isReading=true` to set the user's singleton reading bookmark. Set `isReading=false` to unset the current reading bookmark; in that case the response `data` can be `null` if no reading bookmark was set. For Quran.com-style saved or favorite ayah bookmarks, use `POST /v1/collections/__default__/bookmarks`.",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Add user bookmark",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "The Surah number.",
+ "example": 2
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "verseNumber": {
+ "type": "integer",
+ "description": "The Ayah number to be added.",
+ "example": 3
+ },
+ "isReading": {
+ "type": "boolean",
+ "description": "Reading bookmark flag. Set `true` to set the user's current reading bookmark. Set `false` to unset the current reading bookmark. Omit this field to create or update a regular bookmark."
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key",
+ "type",
+ "verseNumber"
+ ],
+ "additionalProperties": false,
+ "title": "Ayah"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "integer",
+ "description": "Surah, Juz or page number."
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "juz",
+ "page",
+ "surah"
+ ],
+ "description": "The bookmark type.",
+ "example": "surah"
+ },
+ "isReading": {
+ "type": "boolean",
+ "description": "Reading bookmark flag. Set `true` to set the user's current reading bookmark. Set `false` to unset the current reading bookmark. Omit this field to create or update a regular bookmark."
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "mushaf": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ }
+ },
+ "required": [
+ "key",
+ "type"
+ ],
+ "additionalProperties": false,
+ "title": "Surah, Juz, Or page"
+ }
+ ]
+ },
+ "example": {
+ "key": 2,
+ "type": "ayah",
+ "verseNumber": 3,
+ "isReading": true,
+ "mushafId": 4,
+ "mushaf": 4
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/NullableBookmark"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "cmoa3wqim00057z3fe30y0b3e",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "type": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "group": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false,
+ "collectionsCount": 1
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1Bookmarks"
+ },
+ "get": {
+ "description": "Get all bookmarks. This includes bookmarks belonging to a collection.",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Get user bookmarks",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "page",
+ "juz",
+ "surah",
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "required": false,
+ "description": "The bookmark type."
+ },
+ {
+ "in": "query",
+ "name": "isReading",
+ "schema": {
+ "type": "boolean",
+ "description": "Whether to fetch only the reading bookmark"
+ },
+ "required": false,
+ "description": "Whether to fetch only the reading bookmark"
+ },
+ {
+ "in": "query",
+ "name": "key",
+ "schema": {
+ "type": "integer",
+ "description": "Filter by key (surah/juz/page number)"
+ },
+ "required": false,
+ "description": "Filter by key (surah/juz/page number)"
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "required": false,
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "required": false,
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "required": false,
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "required": false,
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/BookmarkWithCollectionsCount"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wqim00057z3fe30y0b3e",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "type": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "group": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false,
+ "collectionsCount": 1
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1Bookmarks"
+ }
+ },
+ "/v1/bookmarks/{bookmarkId}": {
+ "delete": {
+ "description": "Delete a standalone bookmark by id. This endpoint fully removes orphan bookmarks only. If the bookmark belongs to the virtual Favorites collection or any custom collection, it is not removed; this endpoint only sets `isReading` to `false` and leaves the bookmark attached to those collections. To remove it from Favorites or a custom collection, use the corresponding collection delete endpoint instead.",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Delete Bookmark",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "bookmarkId",
+ "schema": {
+ "type": "string",
+ "description": "The id of the bookmark to be deleted.",
+ "example": "cmoa3wqk500077z3f018r4rzn"
+ },
+ "required": true,
+ "description": "The id of the bookmark to be deleted."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "bookmark deleted"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "bookmark deleted"
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1BookmarksByBookmarkId"
+ }
+ },
+ "/v1/bookmarks/ayahs-range": {
+ "get": {
+ "description": "Get all bookmarks within a specific Ayahs range.",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Get bookmarks within a range of Ayahs",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "chapterNumber",
+ "schema": {
+ "type": "integer",
+ "description": "The number of the Surah that the Ayahs range belong to."
+ },
+ "required": true,
+ "description": "The number of the Surah that the Ayahs range belong to."
+ },
+ {
+ "in": "query",
+ "name": "rangeStartAyahNumber",
+ "schema": {
+ "type": "integer",
+ "description": "The Ayah number at which the range starts."
+ },
+ "required": true,
+ "description": "The Ayah number at which the range starts."
+ },
+ {
+ "in": "query",
+ "name": "rangeEndAyahNumber",
+ "schema": {
+ "type": "integer",
+ "description": "The Ayah number at which the range ends."
+ },
+ "required": true,
+ "description": "The Ayah number at which the range ends."
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/RawBookmark"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wqiu00067z3fh6oieeiq",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "bookmarkType": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "bookmarkGroup": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1BookmarksAyahsRange"
+ }
+ },
+ "/v1/bookmarks/bookmark": {
+ "get": {
+ "description": "Get a bookmark by details",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Get bookmark",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "verseNumber",
+ "schema": {
+ "type": "integer",
+ "description": "The Ayah number of the bookmark"
+ },
+ "description": "The Ayah number of the bookmark"
+ },
+ {
+ "in": "query",
+ "name": "isReading",
+ "schema": {
+ "type": "boolean",
+ "description": "Whether to fetch the reading bookmark"
+ },
+ "description": "Whether to fetch the reading bookmark"
+ },
+ {
+ "in": "query",
+ "name": "key",
+ "schema": {
+ "type": "integer",
+ "oneOf": [
+ {},
+ {
+ "x-required": true
+ }
+ ],
+ "description": "Surah, Juz or page number.",
+ "example": 2
+ },
+ "description": "Surah, Juz or page number."
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "page",
+ "juz",
+ "surah",
+ "ayah"
+ ],
+ "oneOf": [
+ {},
+ {
+ "x-required": true
+ }
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "description": "The bookmark type."
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name.",
+ "example": 4
+ },
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Preferred field name."
+ },
+ {
+ "in": "query",
+ "name": "mushaf",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`.",
+ "example": 4
+ },
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4 Legacy alias for `mushafId`."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/Bookmark"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "cmoa3wqim00057z3fe30y0b3e",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "type": "ayah",
+ "key": 1,
+ "verseNumber": 5,
+ "group": "verses_6236",
+ "isInDefaultCollection": true,
+ "isReading": false,
+ "collectionsCount": 1
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1BookmarksBookmark"
+ }
+ },
+ "/v1/bookmarks/collections": {
+ "get": {
+ "description": "Get named collection IDs for a bookmark by bookmark details. Pass `includeDefault=true` to also append `__default__` when the bookmark belongs to Favorites.",
+ "tags": [
+ "Bookmarks"
+ ],
+ "summary": "Get bookmark collections",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "key",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "Surah, Juz or page number."
+ },
+ "required": true,
+ "description": "Surah, Juz or page number."
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "page",
+ "juz",
+ "surah",
+ "ayah"
+ ],
+ "description": "The bookmark type.",
+ "default": "ayah"
+ },
+ "required": false,
+ "description": "The bookmark type."
+ },
+ {
+ "in": "query",
+ "name": "includeDefault",
+ "schema": {
+ "type": "boolean",
+ "description": "When `true`, append `__default__` if the bookmark belongs to the virtual Favorites collection."
+ },
+ "required": false,
+ "description": "When `true`, append `__default__` if the bookmark belongs to the virtual Favorites collection."
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "required": false,
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "required": false,
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "required": false,
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "required": false,
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "Collection ID. When `includeDefault=true`, this array may also include `__default__`.",
+ "example": "cmnkcpmvc000814v9f5jtbsxf"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ "cmnkcpmvc000814v9f5jtbsxf"
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1BookmarksCollections"
+ }
+ },
+ "/v1/preferences": {
+ "post": {
+ "description": "Add or update one user preferences group like favorite Tafsirs or translations.",
+ "tags": [
+ "Preferences"
+ ],
+ "summary": "Add or update preference",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "group": {
+ "type": "string",
+ "enum": [
+ "tafsirs",
+ "translations",
+ "audio",
+ "theme",
+ "quranReaderStyles",
+ "reading",
+ "language",
+ "userHasCustomised"
+ ],
+ "description": "The preference group to be added or updated.",
+ "example": "tafsirs"
+ },
+ "key": {
+ "type": "string",
+ "description": "The preference key to be added or updated.",
+ "example": "selectedTafsirs"
+ },
+ "value": {
+ "description": "The preference value to be added or updated.",
+ "example": "[\"en-tafisr-ibn-kathir\"]"
+ }
+ },
+ "required": [
+ "group",
+ "key",
+ "value"
+ ],
+ "additionalProperties": false,
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "type"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "readingPreference",
+ "selectedWordByWordLocale",
+ "wordClickFunctionality",
+ "isReadingByRevelationOrder",
+ "wordByWordContentType",
+ "wordByWordDisplay",
+ "wordByWordTooltipContentType",
+ "wordByWordInlineContentType",
+ "selectedReadingTranslation",
+ "selectedReflectionLanguages",
+ "selectedLessonLanguages"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "tafsirFontScale",
+ "quranTextFontScale",
+ "translationFontScale",
+ "wordByWordFontScale",
+ "reflectionFontScale",
+ "qnaFontScale",
+ "lessonFontScale",
+ "surahInfoFontScale",
+ "hadithFontScale",
+ "layersFontScale",
+ "quranFont",
+ "mushafLines",
+ "showTajweedRules"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "selectedTranslations"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "selectedTafsirs"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "reciter",
+ "playbackRate",
+ "showTooltipWhenPlayingAudio",
+ "enableAutoScrolling",
+ "repeatSettings"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "language"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "en",
+ "ar",
+ "bn",
+ "fa",
+ "fr",
+ "id",
+ "it",
+ "nl",
+ "pt",
+ "ru",
+ "sq",
+ "th",
+ "tr",
+ "ur",
+ "zh",
+ "ms",
+ "es",
+ "sw",
+ "vi"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "auto",
+ "light",
+ "sepia",
+ "dark"
+ ],
+ "example": "auto"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "reading",
+ "readingTranslation"
+ ],
+ "example": "translation"
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "en",
+ "ur",
+ "id",
+ "bn",
+ "tr",
+ "fa",
+ "ru",
+ "hi",
+ "de",
+ "ta",
+ "inh",
+ "fr",
+ "sq",
+ "dv",
+ "zh",
+ "sd",
+ "ml"
+ ],
+ "example": "en"
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "play-audio",
+ "no-audio"
+ ],
+ "example": "play-audio"
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "boolean",
+ "example": true
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "transliteration"
+ ]
+ },
+ "example": [
+ "translation"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "tooltip",
+ "inline"
+ ]
+ },
+ "example": [
+ "tooltip"
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "translation",
+ "transliteration"
+ ]
+ },
+ "example": []
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "code_v1",
+ "code_v2",
+ "text_uthmani",
+ "text_indopak",
+ "qpc_uthmani_hafs",
+ "tajweed",
+ "tajweed_v4"
+ ],
+ "example": "code_v1"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "enum": [
+ "15_lines",
+ "16_lines"
+ ],
+ "example": "16_lines"
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 10,
+ "example": 3
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 6,
+ "example": 3
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "example": 131
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "example": "en-tafisr-ibn-kathir"
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "integer",
+ "enum": [
+ 0.25,
+ 0.5,
+ 0.75,
+ 1,
+ 1.25,
+ 1.5,
+ 1.75,
+ 2
+ ],
+ "example": 1
+ }
+ },
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "userHasCustomised"
+ ]
+ }
+ },
+ "required": [
+ "key"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "example": "131"
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "maxLength": 10
+ },
+ "minItems": 1
+ }
+ },
+ "required": [
+ "value"
+ ],
+ "additionalProperties": false
+ }
+ ]
+ },
+ "example": {
+ "key": "type"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "preference updated"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "preference updated"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1Preferences"
+ },
+ "get": {
+ "description": "Get all user preferences like theme, favorite reciter, default language etc.",
+ "tags": [
+ "Preferences"
+ ],
+ "summary": "Get user preferences",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/Preference"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "theme": {
+ "type": "auto"
+ },
+ "reading": {
+ "readingPreference": "translation",
+ "selectedWordByWordLocale": "en",
+ "wordClickFunctionality": "play-audio",
+ "isReadingByRevelationOrder": true,
+ "wordByWordContentType": [
+ "translation"
+ ],
+ "wordByWordDisplay": [
+ "tooltip"
+ ],
+ "wordByWordTooltipContentType": [
+ "translation"
+ ],
+ "wordByWordInlineContentType": [],
+ "selectedReadingTranslation": "131",
+ "selectedReflectionLanguages": [
+ "string"
+ ],
+ "selectedLessonLanguages": [
+ "string"
+ ]
+ },
+ "quranReaderStyles": {
+ "tafsirFontScale": 3,
+ "quranTextFontScale": 3,
+ "translationFontScale": 3,
+ "wordByWordFontScale": 3,
+ "reflectionFontScale": 3,
+ "qnaFontScale": 3,
+ "lessonFontScale": 3,
+ "surahInfoFontScale": 3,
+ "hadithFontScale": 3,
+ "layersFontScale": 3,
+ "quranFont": "code_v1",
+ "mushafLines": "16_lines",
+ "showTajweedRules": true
+ },
+ "translations": {
+ "selectedTranslations": [
+ 131
+ ]
+ },
+ "tafsirs": {
+ "selectedTafsirs": [
+ "en-tafisr-ibn-kathir"
+ ]
+ },
+ "audio": {
+ "reciter": 7,
+ "playbackRate": 1,
+ "showTooltipWhenPlayingAudio": true,
+ "enableAutoScrolling": true
+ },
+ "language": {
+ "language": "en"
+ },
+ "userHasCustomised": {
+ "userHasCustomised": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1Preferences"
+ }
+ },
+ "/v1/preferences/bulk": {
+ "post": {
+ "description": "Add or update one or more user preferences groups like favorite Tafsirs and translations.",
+ "tags": [
+ "Preferences"
+ ],
+ "summary": "Bulk add or update preferences",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Preference"
+ },
+ "example": {
+ "theme": {
+ "type": "auto"
+ },
+ "reading": {
+ "readingPreference": "translation",
+ "selectedWordByWordLocale": "en",
+ "wordClickFunctionality": "play-audio",
+ "isReadingByRevelationOrder": true,
+ "wordByWordContentType": [
+ "translation"
+ ],
+ "wordByWordDisplay": [
+ "tooltip"
+ ],
+ "wordByWordTooltipContentType": [
+ "translation"
+ ],
+ "wordByWordInlineContentType": [],
+ "selectedReadingTranslation": "131",
+ "selectedReflectionLanguages": [
+ "string"
+ ],
+ "selectedLessonLanguages": [
+ "string"
+ ]
+ },
+ "quranReaderStyles": {
+ "tafsirFontScale": 3,
+ "quranTextFontScale": 3,
+ "translationFontScale": 3,
+ "wordByWordFontScale": 3,
+ "reflectionFontScale": 3,
+ "qnaFontScale": 3,
+ "lessonFontScale": 3,
+ "surahInfoFontScale": 3,
+ "hadithFontScale": 3,
+ "layersFontScale": 3,
+ "quranFont": "code_v1",
+ "mushafLines": "16_lines",
+ "showTajweedRules": true
+ },
+ "translations": {
+ "selectedTranslations": [
+ 131
+ ]
+ },
+ "tafsirs": {
+ "selectedTafsirs": [
+ "en-tafisr-ibn-kathir"
+ ]
+ },
+ "audio": {
+ "reciter": 7,
+ "playbackRate": 1,
+ "showTooltipWhenPlayingAudio": true,
+ "enableAutoScrolling": true
+ },
+ "language": {
+ "language": "en"
+ },
+ "userHasCustomised": {
+ "userHasCustomised": false
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "preferences updated"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "preferences updated"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1PreferencesBulk"
+ }
+ },
+ "/v1/reading-sessions": {
+ "post": {
+ "description": "Track the user's most recent reading location (Surah/Ayah) for \"Continue reading\" / \"Recently read\" UX.\n\nA new reading session will be created if the user does not have an existing one in the past 20 minutes; otherwise, the existing reading session will be updated with the latest read Ayah.\n\nFor streaks, goals, and calendar-style progress tracking, see [Reading Sessions vs Activity Days](/docs/user-related-apis/reading-sessions-vs-activity-days).",
+ "tags": [
+ "Reading Sessions"
+ ],
+ "summary": "Add or update user reading session",
+ "parameters": [],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "chapterNumber": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The Surah number to be added to reading session.",
+ "example": 1
+ },
+ "verseNumber": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The Ayah number to be added to reading session.",
+ "example": 1
+ }
+ },
+ "required": [
+ "chapterNumber",
+ "verseNumber"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "chapterNumber": 1,
+ "verseNumber": 1
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "enum": [
+ "reading session created",
+ "reading session updated"
+ ],
+ "example": "reading session created"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "reading session created"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1ReadingSessions"
+ },
+ "get": {
+ "description": "Get the user's reading sessions (most recent first). Reading sessions track recent Surah/Ayah locations for \"Continue reading\" / \"Recently read\". For streaks, goals, and calendar-style progress tracking, use Activity Days.",
+ "tags": [
+ "Reading Sessions"
+ ],
+ "summary": "Get user reading sessions",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ReadingSession"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wrpk000h7z3f2t6a57dg",
+ "updatedAt": "2023-01-21T07:28:13.023Z",
+ "chapterNumber": 1,
+ "verseNumber": 5
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1ReadingSessions"
+ }
+ },
+ "/v1/goals/get-todays-plan": {
+ "get": {
+ "description": "Get today's goal plan.",
+ "tags": [
+ "Goals"
+ ],
+ "summary": "Get today's goal plan",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN_TIME",
+ "QURAN_PAGES",
+ "QURAN_RANGE",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The type of the goal.",
+ "example": "QURAN_TIME"
+ },
+ "required": true,
+ "description": "The type of the goal."
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "hasGoal": {
+ "type": "boolean",
+ "description": "User has a goal.",
+ "example": false
+ }
+ },
+ "required": [
+ "hasGoal"
+ ],
+ "additionalProperties": false,
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The id of the activity day.",
+ "example": "cmoa3wq2b00047z3fbl4c6ew0"
+ },
+ "date": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date of the activity day.",
+ "example": "2023-09-31"
+ },
+ "progress": {
+ "type": "number",
+ "format": "float",
+ "minimum": 0,
+ "maximum": 1,
+ "description": "The progress of the reading goal of that activity day (if the user has a reading goal on that day).",
+ "example": 0.695
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "LESSON",
+ "QURAN_READING_PROGRAM"
+ ],
+ "description": "The type of the activity day",
+ "example": "QURAN"
+ },
+ "ranges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The ranges read on that day (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "pagesRead": {
+ "oneOf": [
+ {
+ "type": "number",
+ "format": "float"
+ }
+ ],
+ "description": "The number of pages read on that day (will be included only when the type is QURAN)",
+ "example": 1.637041020126048
+ },
+ "secondsRead": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds spent reading on that day (will be included only when the type is QURAN)",
+ "example": 417
+ },
+ "versesRead": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of Ayahs read on that day (will be included only when the type is QURAN)",
+ "example": 24
+ },
+ "manuallyAddedSeconds": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds spent reading that was manually input by the user and not auto-tracked (will be included only when the type is QURAN)",
+ "example": 24
+ },
+ "dailyTargetPages": {
+ "oneOf": [
+ {
+ "type": "number",
+ "format": "float"
+ }
+ ],
+ "description": "The number of pages user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": 1.637041020126048
+ },
+ "dailyTargetSeconds": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": 5
+ },
+ "dailyTargetRanges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "remainingDailyTargetRanges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The remaining range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ }
+ },
+ "required": [
+ "id",
+ "date",
+ "progress",
+ "type",
+ "mushafId"
+ ],
+ "additionalProperties": false,
+ "description": "The Mushaf used to read on that day (will be included only when the type is QURAN) \n\nThe id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "title": "When user has a goal"
+ }
+ ]
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "cmoa3wq2b00047z3fbl4c6ew0",
+ "date": "2023-09-31",
+ "progress": 0.695,
+ "type": "QURAN",
+ "ranges": [
+ "1:1-1:2"
+ ],
+ "pagesRead": 1.637041020126048,
+ "secondsRead": 417,
+ "versesRead": 24,
+ "manuallyAddedSeconds": 24,
+ "dailyTargetPages": 1.637041020126048,
+ "dailyTargetSeconds": 5,
+ "dailyTargetRanges": [
+ "1:1-1:2"
+ ],
+ "remainingDailyTargetRanges": [
+ "1:1-1:2"
+ ],
+ "mushafId": 4
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1GoalsGetTodaysPlan"
+ }
+ },
+ "/v1/goals/{id}": {
+ "put": {
+ "description": "Update a goal",
+ "tags": [
+ "Goals"
+ ],
+ "summary": "Update a goal",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "schema": {
+ "type": "string",
+ "description": "The id of the goal.",
+ "example": "cmoa3wr5c000g7z3fgv0y0rvo"
+ },
+ "required": true,
+ "description": "The id of the goal."
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "QURAN_TIME",
+ "QURAN_PAGES",
+ "QURAN_RANGE",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The type of the goal.",
+ "example": "QURAN_TIME"
+ },
+ "amount": {
+ "oneOf": [
+ {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$",
+ "example": "1:5-1:10",
+ "x-required": true
+ },
+ {
+ "type": "integer",
+ "minimum": 1,
+ "example": 600,
+ "x-required": true
+ }
+ ],
+ "description": "The amount of the goal. Depending on the goal type, the amount value and format will be different"
+ },
+ "duration": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."
+ },
+ "category": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The category of the goal"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "type": "QURAN_TIME",
+ "amount": "1:5-1:10",
+ "duration": 1,
+ "category": "QURAN"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {}
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPutV1GoalsById"
+ },
+ "delete": {
+ "description": "Delete a goal by id.",
+ "tags": [
+ "Goals"
+ ],
+ "summary": "Delete a goal",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "schema": {
+ "type": "string",
+ "description": "The id of the goal.",
+ "example": "cmoa3wr5c000g7z3fgv0y0rvo"
+ },
+ "required": true,
+ "description": "The id of the goal."
+ },
+ {
+ "in": "query",
+ "name": "category",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The category of the goal"
+ },
+ "required": true,
+ "description": "The category of the goal"
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "enum": [
+ "goal deleted"
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "message": "goal deleted"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1GoalsById"
+ }
+ },
+ "/v1/goals": {
+ "post": {
+ "description": "Create a goal",
+ "tags": [
+ "Goals"
+ ],
+ "summary": "Create a goal",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "QURAN_TIME",
+ "QURAN_PAGES",
+ "QURAN_RANGE",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The type of the goal.",
+ "example": "QURAN_TIME"
+ },
+ "amount": {
+ "oneOf": [
+ {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$",
+ "example": "1:5-1:10",
+ "x-required": true
+ },
+ {
+ "type": "integer",
+ "minimum": 1,
+ "example": 600,
+ "x-required": true
+ }
+ ],
+ "description": "The amount of the goal. Depending on the goal type, the amount value and format will be different"
+ },
+ "duration": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."
+ },
+ "category": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The category of the goal"
+ }
+ },
+ "required": [
+ "type",
+ "amount",
+ "category"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "type": "QURAN_TIME",
+ "amount": "1:5-1:10",
+ "duration": 1,
+ "category": "QURAN"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The id of the goal.",
+ "example": "cmoa3wr5c000g7z3fgv0y0rvo"
+ }
+ },
+ "required": [
+ "id"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "cmoa3wr5c000g7z3fgv0y0rvo"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1Goals"
+ }
+ },
+ "/v1/goals/estimate": {
+ "get": {
+ "description": "Generate a timeline up to a week of the minimum daily amount required to meet the goal.",
+ "tags": [
+ "Goals"
+ ],
+ "summary": "Generate timeline estimation",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN_TIME",
+ "QURAN_PAGES",
+ "QURAN_RANGE",
+ "COURSE",
+ "QURAN_READING_PROGRAM",
+ "RAMADAN_CHALLENGE"
+ ],
+ "description": "The type of the goal.",
+ "example": "QURAN_TIME"
+ },
+ "required": true,
+ "description": "The type of the goal."
+ },
+ {
+ "in": "query",
+ "name": "amount",
+ "schema": {
+ "oneOf": [
+ {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$",
+ "example": "1:5-1:10",
+ "x-required": true
+ },
+ {
+ "type": "integer",
+ "minimum": 1,
+ "example": 600,
+ "x-required": true
+ }
+ ],
+ "description": "The amount of the goal. Depending on the goal type, the amount value and format will be different"
+ },
+ "required": true,
+ "description": "The amount of the goal. Depending on the goal type, the amount value and format will be different"
+ },
+ {
+ "in": "query",
+ "name": "duration",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."
+ },
+ "required": false,
+ "description": "The duration of the goal in days. If it's empty it means the goal is a daily goal and not duration-based."
+ },
+ {
+ "in": "query",
+ "name": "mushafId",
+ "schema": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ },
+ "required": true,
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "$ref": "#/components/schemas/EstimatedGoalTimeline"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "week": [
+ {
+ "date": "2023-01-21T07:28:13.023Z",
+ "amount": "1:5-1:10"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1GoalsEstimate"
+ }
+ },
+ "/v1/streaks": {
+ "get": {
+ "description": "Get user streaks.",
+ "tags": [
+ "Streaks"
+ ],
+ "summary": "Get streaks",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "from",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date after which any streaks would be returned (inclusive)",
+ "example": "2023-09-01"
+ },
+ "description": "The date after which any streaks would be returned (inclusive)"
+ },
+ {
+ "in": "query",
+ "name": "to",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date before which any streaks would be returned (inclusive)",
+ "example": "2023-09-31"
+ },
+ "description": "The date before which any streaks would be returned (inclusive)"
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN"
+ ],
+ "description": "The type of the streak",
+ "example": "QURAN"
+ },
+ "description": "The type of the streak"
+ },
+ {
+ "in": "query",
+ "name": "sortOrder",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "description": "The sorting order of `orderBy` field",
+ "example": "desc",
+ "default": "desc"
+ },
+ "description": "The sorting order of `orderBy` field"
+ },
+ {
+ "in": "query",
+ "name": "orderBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "startDate",
+ "days"
+ ],
+ "description": "Which field to order the streaks by",
+ "example": "startDate",
+ "default": "startDate"
+ },
+ "description": "Which field to order the streaks by"
+ },
+ {
+ "in": "query",
+ "name": "status",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "ACTIVE",
+ "BROKEN"
+ ],
+ "description": "The status of the streak.",
+ "example": "ACTIVE"
+ },
+ "description": "The status of the streak."
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The id of the streak.",
+ "example": "cmoa3wrr2000i7z3fe8swbujv"
+ },
+ "startDate": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date of the streak.",
+ "example": "2023-09-01"
+ },
+ "endDate": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date of the streak.",
+ "example": "2023-09-31"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "ACTIVE",
+ "BROKEN"
+ ],
+ "description": "The status of the streak.",
+ "example": "ACTIVE"
+ },
+ "days": {
+ "type": "integer",
+ "description": "The number of days the streak is/was active for.",
+ "example": 5
+ }
+ },
+ "required": [
+ "id",
+ "startDate",
+ "endDate",
+ "status",
+ "days"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wrr2000i7z3fe8swbujv",
+ "startDate": "2023-09-01",
+ "endDate": "2023-09-31",
+ "status": "ACTIVE",
+ "days": 5
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1Streaks"
+ }
+ },
+ "/v1/streaks/current-streak-days": {
+ "get": {
+ "description": "Get current active streak days.",
+ "tags": [
+ "Streaks"
+ ],
+ "summary": "Get current streak days",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN"
+ ],
+ "description": "The type of the streak",
+ "example": "QURAN"
+ },
+ "required": true,
+ "description": "The type of the streak"
+ },
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "days": {
+ "type": "integer",
+ "description": "The number of days the current streak is active for.",
+ "example": 5
+ }
+ },
+ "required": [
+ "days"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "days": 5
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1StreaksCurrentStreakDays"
+ }
+ },
+ "/v1/activity-days": {
+ "post": {
+ "description": "Create or update a daily activity record (one per date per type). Activity Days power streaks, goals, and calendar-style progress.\n\nFor `type=QURAN`, provide `seconds`, `ranges`, and `mushafId`. You can optionally pass `date` (YYYY-MM-DD) to backfill activity for a past day (for example when the user manually adds time). This endpoint enqueues progress updates and uses the `x-timezone` header to interpret day boundaries and calculate streaks accurately.",
+ "tags": [
+ "Activity Days"
+ ],
+ "summary": "Add/update activity day",
+ "parameters": [
+ {
+ "in": "header",
+ "name": "x-timezone",
+ "schema": {
+ "type": "string",
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks.",
+ "example": "Asia/Saigon"
+ },
+ "description": "The current timezone of the user. Not providing the value might affect the accuracy of how we calculate days and streaks."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "date": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date of the activity day, can be today or a past date. If not passed, default to today",
+ "example": "2023-09-01"
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "LESSON",
+ "QURAN_READING_PROGRAM"
+ ],
+ "description": "The type of the activity day",
+ "example": "QURAN"
+ }
+ },
+ "required": [
+ "type"
+ ],
+ "additionalProperties": false,
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "seconds": {
+ "type": "integer",
+ "minimum": 1,
+ "description": "Seconds spent reading the current request's ranges",
+ "example": 5
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ },
+ "description": "Current request's read range of Ayahs",
+ "example": [
+ "1:5-1:10"
+ ]
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ }
+ },
+ "required": [
+ "seconds",
+ "ranges",
+ "mushafId"
+ ],
+ "additionalProperties": false,
+ "title": "QURAN"
+ }
+ ]
+ },
+ "example": {
+ "seconds": 5,
+ "ranges": [
+ "1:5-1:10"
+ ],
+ "mushafId": 4
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object"
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {}
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1ActivityDays"
+ },
+ "get": {
+ "description": "Get the user's activity days (calendar/history). Use the `from`/`to` query params to filter by date range and `type` to filter by activity type.",
+ "tags": [
+ "Activity Days"
+ ],
+ "summary": "Get activity days",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "from",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The start date of the activity days",
+ "example": "2023-09-01"
+ },
+ "description": "The start date of the activity days"
+ },
+ {
+ "in": "query",
+ "name": "to",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The last date of the activity days",
+ "example": "2023-09-31"
+ },
+ "description": "The last date of the activity days"
+ },
+ {
+ "in": "query",
+ "name": "dateOrderBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "asc",
+ "desc"
+ ],
+ "description": "Order by activity day's date",
+ "example": "desc",
+ "default": "desc"
+ },
+ "description": "Order by activity day's date"
+ },
+ {
+ "in": "query",
+ "name": "type",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "LESSON",
+ "QURAN_READING_PROGRAM"
+ ],
+ "description": "The type of the activity day",
+ "example": "QURAN"
+ },
+ "description": "The type of the activity day"
+ },
+ {
+ "in": "query",
+ "name": "last",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "description": "The number of items to be fetched. Should be used together with `before`",
+ "example": 10
+ },
+ "description": "The number of items to be fetched. Should be used together with `before`"
+ },
+ {
+ "in": "query",
+ "name": "first",
+ "schema": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 20,
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of items to be fetched.",
+ "example": 10
+ },
+ "description": "The number of items to be fetched."
+ },
+ {
+ "in": "query",
+ "name": "after",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`",
+ "example": "cmoa3wq0z00007z3fh1v9g30d"
+ },
+ "description": "The cursor after which you want to get the next page of items. Should be used together with `first`"
+ },
+ {
+ "in": "query",
+ "name": "before",
+ "schema": {
+ "type": "string",
+ "oneOf": [
+ {
+ "type": "string"
+ }
+ ],
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`",
+ "example": "cmoa3wq1000017z3f9atfhuvw"
+ },
+ "description": "The cursor before which the previous page of items will be fetched. Should be used together with `last`"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The id of the activity day.",
+ "example": "cmoa3wq2b00047z3fbl4c6ew0"
+ },
+ "date": {
+ "type": "string",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
+ "description": "The date of the activity day.",
+ "example": "2023-09-31"
+ },
+ "progress": {
+ "type": "number",
+ "format": "float",
+ "minimum": 0,
+ "maximum": 1,
+ "description": "The progress of the reading goal of that activity day (if the user has a reading goal on that day).",
+ "example": 0.695
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "QURAN",
+ "LESSON",
+ "QURAN_READING_PROGRAM"
+ ],
+ "description": "The type of the activity day",
+ "example": "QURAN"
+ },
+ "ranges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The ranges read on that day (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "pagesRead": {
+ "oneOf": [
+ {
+ "type": "number",
+ "format": "float"
+ }
+ ],
+ "description": "The number of pages read on that day (will be included only when the type is QURAN)",
+ "example": 1.637041020126048
+ },
+ "secondsRead": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds spent reading on that day (will be included only when the type is QURAN)",
+ "example": 417
+ },
+ "versesRead": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of Ayahs read on that day (will be included only when the type is QURAN)",
+ "example": 24
+ },
+ "manuallyAddedSeconds": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds spent reading that was manually input by the user and not auto-tracked (will be included only when the type is QURAN)",
+ "example": 24
+ },
+ "dailyTargetPages": {
+ "oneOf": [
+ {
+ "type": "number",
+ "format": "float"
+ }
+ ],
+ "description": "The number of pages user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": 1.637041020126048
+ },
+ "dailyTargetSeconds": {
+ "oneOf": [
+ {
+ "type": "integer"
+ }
+ ],
+ "description": "The number of seconds user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": 5
+ },
+ "dailyTargetRanges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "remainingDailyTargetRanges": {
+ "oneOf": [
+ {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ }
+ }
+ ],
+ "description": "The remaining range of Ayahs user should read on that day to meet their goal's target if a goal was set (will be included only when the type is QURAN)",
+ "example": [
+ "1:1-1:2"
+ ]
+ },
+ "mushafId": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 11,
+ 19
+ ],
+ "description": "The id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4",
+ "example": 4
+ }
+ },
+ "required": [
+ "id",
+ "date",
+ "progress",
+ "type",
+ "mushafId"
+ ],
+ "additionalProperties": false,
+ "description": "The Mushaf used to read on that day (will be included only when the type is QURAN) \n\nThe id of the Mushaf being used. \n\n1 = QCFV2 \n\n 2 = QCFV1 \n\n 3 = Indopak \n\n 4 = UthmaniHafs \n\n 5 = KFGQPCHAFS \n\n 6 = Indopak15Lines \n\n 7 = Indopak16Lines \n\n 11 = Tajweeed \n\n 19 = QCFTajweedV4"
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "cmoa3wq2b00047z3fbl4c6ew0",
+ "date": "2023-09-31",
+ "progress": 0.695,
+ "type": "QURAN",
+ "ranges": [
+ "1:1-1:2"
+ ],
+ "pagesRead": 1.637041020126048,
+ "secondsRead": 417,
+ "versesRead": 24,
+ "manuallyAddedSeconds": 24,
+ "dailyTargetPages": 1.637041020126048,
+ "dailyTargetSeconds": 5,
+ "dailyTargetRanges": [
+ "1:1-1:2"
+ ],
+ "remainingDailyTargetRanges": [
+ "1:1-1:2"
+ ],
+ "mushafId": 4
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1ActivityDays"
+ }
+ },
+ "/v1/activity-days/estimate-reading-time": {
+ "get": {
+ "description": "Estimate the number of seconds it would take to read a range. We estimate it based on the average reading speed we have collected on quran.com.",
+ "tags": [
+ "Activity Days"
+ ],
+ "summary": "Estimate reading time",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "ranges",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+:\\d+-\\d+:\\d+(?:,\\d+:\\d+-\\d+:\\d+)*)$",
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2",
+ "example": "1:1-1:2"
+ },
+ "required": true,
+ "description": "a comma separated string of Ayah ranges e.g. 1:1-1:2"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "seconds": {
+ "type": "integer",
+ "description": "The number of seconds it would take on average to read the range of Ayahs.",
+ "example": 66.8
+ }
+ },
+ "required": [
+ "seconds"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "seconds": 66.8
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1ActivityDaysEstimateReadingTime"
+ }
+ },
+ "/v1/users/profile": {
+ "patch": {
+ "operationId": "UsersController_editProfile",
+ "summary": "Edit user profile",
+ "description": "Partially update the authenticated user settings and preferences like notification settings, privacy options, and display preferences.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Settings fields to update - only include fields you want to change",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/EditProfileDto"
+ },
+ "example": {
+ "languageId": 1,
+ "reflectionLanguages": [
+ "string"
+ ],
+ "ayahLanguages": [
+ "string"
+ ],
+ "customized": true,
+ "hideFollowSuggestion": true,
+ "showFollowFeaturedSuggestion": true
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Settings updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "success": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid settings data"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "get": {
+ "operationId": "UsersController_profile",
+ "summary": "Get user profile",
+ "description": "Retrieve the complete profile of the authenticated user including personal info, settings, statistics, and connected accounts.",
+ "parameters": [
+ {
+ "name": "qdc",
+ "required": false,
+ "in": "query",
+ "description": "Include Quran.com (QDC) connected account data",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Full user profile with all data",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserSerializedDto"
+ },
+ "example": {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "put": {
+ "operationId": "UsersController_updateProfile",
+ "summary": "Update user profile",
+ "description": "Update user profile information including name, bio, username, avatar, and social links. Validates username uniqueness.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Profile fields to update wrapped in a user object",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateProfileBodyDto"
+ },
+ "example": {
+ "user": {
+ "avatar": "string",
+ "firstName": "string",
+ "lastName": "string",
+ "bio": "string",
+ "country": "string",
+ "removeAvatar": true
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Profile updated and returned with new values",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserSerializedDto"
+ },
+ "example": {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid profile data or username taken"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/notes": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "List notes owned by the user. This API contains pagination. Read more about [pagination](/#pagination)",
+ "summary": "Get all notes",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "cursor",
+ "schema": {
+ "type": "string",
+ "description": "A cursor for pagination, used to fetch the next set of results.",
+ "example": "cursor123"
+ },
+ "description": "A cursor for pagination, used to fetch the next set of results."
+ },
+ {
+ "in": "query",
+ "name": "limit",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "minimum": 1,
+ "maximum": 50,
+ "description": "The maximum number of notes to return, defaults to 20.",
+ "example": 20,
+ "default": 20
+ },
+ "description": "The maximum number of notes to return, defaults to 20."
+ },
+ {
+ "in": "query",
+ "name": "sortBy",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "newest",
+ "oldest"
+ ],
+ "description": "The sorting order of the notes, defaults to newest first.",
+ "example": "newest",
+ "default": "newest"
+ },
+ "description": "The sorting order of the notes, defaults to newest first."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1Notes"
+ },
+ "post": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Add a new note.",
+ "summary": "Add note",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "saveToQR": {
+ "type": "boolean",
+ "description": "Indicates whether the note should be saved to the QuranReflect.",
+ "example": true
+ },
+ "attachedEntity": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "body",
+ "saveToQR"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "body": "This is a sample note body.",
+ "saveToQR": true,
+ "attachedEntity": {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ },
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1Notes"
+ }
+ },
+ "/v1/notes/by-verse/{verseKey}": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Retrieve notes by a specific verse.",
+ "summary": "Get notes by verse",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "verseKey",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)$",
+ "description": "The verse key for which notes are being requested.",
+ "example": "2:255"
+ },
+ "required": true,
+ "description": "The verse key for which notes are being requested."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "pagination": {
+ "type": "object",
+ "properties": {
+ "startCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000027z3fciij2440"
+ },
+ "endCursor": {
+ "type": "string",
+ "example": "cmoa3wq1000037z3fhr8z3edp"
+ },
+ "hasNextPage": {
+ "type": "boolean",
+ "example": true
+ },
+ "hasPreviousPage": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ ],
+ "pagination": {
+ "startCursor": "cmoa3wq1000027z3fciij2440",
+ "endCursor": "cmoa3wq1000037z3fhr8z3edp",
+ "hasNextPage": true,
+ "hasPreviousPage": false
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1NotesByVerseByVerseKey"
+ }
+ },
+ "/v1/notes/by-attached-entity": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Retrieve notes by attached entity.",
+ "summary": "Get notes by attached entity",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "entityId",
+ "schema": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "required": true,
+ "description": "The unique identifier for the attached entity."
+ },
+ {
+ "in": "query",
+ "name": "entityType",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "required": true,
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1NotesByAttachedEntity"
+ }
+ },
+ "/v1/notes/count-within-range": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Get the count of notes within a range of verses.",
+ "summary": "Get notes count within verse range",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "from",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)$",
+ "description": "The starting verse key of the range.",
+ "example": "2:12"
+ },
+ "required": true,
+ "description": "The starting verse key of the range."
+ },
+ {
+ "in": "query",
+ "name": "to",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)$",
+ "description": "The ending verse key of the range.",
+ "example": "2:18"
+ },
+ "required": true,
+ "description": "The ending verse key of the range."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "description": "A map of verse keys to note counts, where each key is a verse key and each value is an integer count of notes.",
+ "example": {
+ "1:2": 5,
+ "1:3": 1,
+ "1:4": 1
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "1:2": 5,
+ "1:3": 1,
+ "1:4": 1
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1NotesCountWithinRange"
+ }
+ },
+ "/v1/notes/by-range": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Retrieve notes by a range of verses.",
+ "summary": "Get notes by verse range",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "from",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)$",
+ "description": "The starting verse key of the range.",
+ "example": "2:12"
+ },
+ "required": true,
+ "description": "The starting verse key of the range."
+ },
+ {
+ "in": "query",
+ "name": "to",
+ "schema": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)$",
+ "description": "The ending verse key of the range.",
+ "example": "2:18"
+ },
+ "required": true,
+ "description": "The ending verse key of the range."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": [
+ {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1NotesByRange"
+ }
+ },
+ "/v1/notes/{noteId}": {
+ "get": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Retrieve a note by its ID.",
+ "summary": "Get note by ID",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "withAttachedEntities",
+ "schema": {
+ "type": "boolean",
+ "description": "Specifies whether to include attached entities in the response, defaults to true.",
+ "example": true,
+ "default": true
+ },
+ "description": "Specifies whether to include attached entities in the response, defaults to true."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authGetV1NotesByNoteId"
+ },
+ "patch": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Update a note by its ID.",
+ "summary": "Update note by ID",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "noteId",
+ "schema": {
+ "type": "string",
+ "description": "The unique identifier of the note to be retrieved or manipulated.",
+ "example": "asda12312312"
+ },
+ "required": true,
+ "description": "The unique identifier of the note to be retrieved or manipulated."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "saveToQR": {
+ "type": "boolean",
+ "description": "Indicates whether the updated note should be saved to the QuranReflect, defaults to false.",
+ "example": false,
+ "default": false
+ }
+ },
+ "required": [
+ "body"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "body": "This is a sample note body.",
+ "saveToQR": false
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "The unique identifier of the note.",
+ "example": "asdasdqwe1231"
+ },
+ "createdAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The creation date of the note.",
+ "example": "2023-01-21T07:28:13.023Z"
+ },
+ "updatedAt": {
+ "type": "string",
+ "format": "date-time",
+ "description": "The last update date of the note.",
+ "example": "2023-01-22T07:28:13.023Z"
+ },
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of the note.",
+ "example": "we23412312weq"
+ },
+ "attachedEntities": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "entityId": {
+ "type": "string",
+ "description": "The unique identifier for the attached entity.",
+ "example": "entity123"
+ },
+ "entityType": {
+ "type": "string",
+ "enum": [
+ "reflection"
+ ],
+ "description": "The type of the attached entity, must be one of the predefined NoteEntityType values.",
+ "example": "reflection"
+ },
+ "entityMetadata": {
+ "type": "object",
+ "properties": {},
+ "description": "Additional metadata for the attached entity.",
+ "example": {
+ "key": "value"
+ }
+ }
+ },
+ "required": [
+ "entityId",
+ "entityType"
+ ],
+ "additionalProperties": false
+ },
+ "description": "An array of attached entities associated with the note."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:255-2:257"
+ ]
+ }
+ },
+ "required": [
+ "id",
+ "createdAt",
+ "updatedAt",
+ "body"
+ ],
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": "asdasdqwe1231",
+ "createdAt": "2023-01-21T07:28:13.023Z",
+ "updatedAt": "2023-01-22T07:28:13.023Z",
+ "body": "This is a sample note body.",
+ "source": "we23412312weq",
+ "attachedEntities": [
+ {
+ "entityId": "entity123",
+ "entityType": "reflection",
+ "entityMetadata": {
+ "key": "value"
+ }
+ }
+ ],
+ "ranges": [
+ "2:255-2:257"
+ ]
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPatchV1NotesByNoteId"
+ },
+ "delete": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Delete a note by its ID.",
+ "summary": "Delete note by ID",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "noteId",
+ "schema": {
+ "type": "string",
+ "description": "The ID of the note to delete."
+ },
+ "required": true,
+ "description": "The ID of the note to delete."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "success": true
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authDeleteV1NotesByNoteId"
+ }
+ },
+ "/v1/notes/{noteId}/publish": {
+ "post": {
+ "tags": [
+ "Notes"
+ ],
+ "description": "Publish a note to QR.",
+ "summary": "Publish note",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "noteId",
+ "schema": {
+ "type": "string",
+ "description": "The unique identifier of the note to be retrieved or manipulated.",
+ "example": "asda12312312"
+ },
+ "required": true,
+ "description": "The unique identifier of the note to be retrieved or manipulated."
+ },
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. Required for any data modification operation to ensure concurrency control."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "body": {
+ "type": "string",
+ "minLength": 6,
+ "maxLength": 10000,
+ "description": "The main content of the note, must be between the specified minimum and maximum length.",
+ "example": "This is a sample note body."
+ },
+ "ranges": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "pattern": "^(\\d+):(\\d+)-(\\d+):(\\d+)$"
+ },
+ "description": "An array of verse ranges associated with the note.",
+ "example": [
+ "2:112-2:115"
+ ]
+ }
+ },
+ "required": [
+ "body"
+ ],
+ "additionalProperties": false
+ },
+ "example": {
+ "body": "This is a sample note body.",
+ "ranges": [
+ "2:112-2:115"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ },
+ "postId": {
+ "type": "number",
+ "format": "float"
+ }
+ },
+ "required": [
+ "success"
+ ],
+ "additionalProperties": false,
+ "description": "Response object indicating the success of the note publishing operation and the optional post ID if successful.",
+ "example": {
+ "success": true,
+ "postId": 123
+ }
+ }
+ },
+ "additionalProperties": false
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "success": true,
+ "postId": 123
+ }
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "operationId": "authPostV1NotesByNoteIdPublish"
+ }
+ },
+ "/v1/users/my-rooms": {
+ "get": {
+ "operationId": "UsersController_rooms",
+ "summary": "Get logged-in user rooms",
+ "description": "Retrieve all rooms (groups and pages) the authenticated user is a member of. Supports filtering by name and pagination.",
+ "parameters": [
+ {
+ "name": "name",
+ "required": false,
+ "in": "query",
+ "description": "Filter rooms by name",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Rooms per page (default: 10)",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User rooms with pagination metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserRoomsResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "id": 1,
+ "name": "string",
+ "group": "string",
+ "public": true,
+ "roomType": "string",
+ "verified": true,
+ "subdomain": "string",
+ "description": "string",
+ "membersCount": 1,
+ "avatarUrl": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/search": {
+ "get": {
+ "operationId": "UsersController_search",
+ "summary": "Search for users",
+ "description": "Search users by name or username. Supports mentioning in posts, finding users for room invites, and general discovery. Results can be scoped to specific contexts.",
+ "parameters": [
+ {
+ "name": "query",
+ "required": false,
+ "in": "query",
+ "description": "Search term for name/username",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Results per page (default: 10)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "all",
+ "required": false,
+ "in": "query",
+ "description": "Search all users (not just followed)",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "postingAs",
+ "required": false,
+ "in": "query",
+ "description": "Filter for posting-as feature",
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "postingAsUserId",
+ "required": false,
+ "in": "query",
+ "description": "User ID for posting-as context",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "roomId",
+ "required": false,
+ "in": "query",
+ "description": "Room ID for scoped search",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Matching users with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UsersSearchResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "isFollowed": false,
+ "followed": false,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{followeeId}/toggle-follow": {
+ "post": {
+ "operationId": "UsersController_toggleFollow",
+ "summary": "Toggle follow/unfollow a user",
+ "description": "Follow or unfollow another user. When following, their posts will appear in your FOLLOWING feed. Can optionally specify action to force follow/unfollow.",
+ "parameters": [
+ {
+ "name": "followeeId",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the user to follow/unfollow",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": false,
+ "description": "Optional: specify \"follow\" or \"unfollow\" action explicitly",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ToggleFollowDto"
+ },
+ "example": {
+ "action": "follow"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Follow status changed - returns new state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "followed": {
+ "type": "boolean",
+ "description": "true if now following"
+ }
+ }
+ },
+ "example": {
+ "followed": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Cannot follow yourself or action already in desired state"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{followerId}/remove-follower": {
+ "post": {
+ "operationId": "UsersController_removeFollower",
+ "summary": "Remove a follower",
+ "description": "Remove a user from your followers list. They will no longer see you as followed and won't receive notifications about your activity.",
+ "parameters": [
+ {
+ "name": "followerId",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the follower to remove",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Follower removed successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "removed": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "removed": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid follower id or follower relationship doesn't exist"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{id}": {
+ "get": {
+ "operationId": "UsersController_getUserProfile",
+ "summary": "Get user profile by id or username",
+ "description": "Retrieve a user profile by either UUID or username. If viewing your own profile, returns full data; otherwise returns public profile with follow relationship status.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": false,
+ "in": "path",
+ "description": "UUID of the user",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "username",
+ "required": false,
+ "in": "path",
+ "description": "Username of the user (case-insensitive)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "qdc",
+ "required": false,
+ "in": "query",
+ "description": "Include Quran.com connected account data",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Own profile with full data including settings",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserSerializedDto"
+ },
+ "example": {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "User not found"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{username}/profile": {
+ "get": {
+ "operationId": "UsersController_getUserProfile",
+ "summary": "Get user profile by id or username",
+ "description": "Retrieve a user profile by either UUID or username. If viewing your own profile, returns full data; otherwise returns public profile with follow relationship status.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": false,
+ "in": "path",
+ "description": "UUID of the user",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "username",
+ "required": false,
+ "in": "path",
+ "description": "Username of the user (case-insensitive)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "qdc",
+ "required": false,
+ "in": "query",
+ "description": "Include Quran.com connected account data",
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Own profile with full data including settings",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UserSerializedDto"
+ },
+ "example": {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "User not found"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{id}/followers": {
+ "get": {
+ "operationId": "UsersController_getUserFollowers",
+ "summary": "Get user followers",
+ "description": "Retrieve a paginated list of users who follow the specified user. Includes follow relationship to the viewer if authenticated.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the user",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Results per page (default: 10)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "List of followers with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UsersSearchResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "isFollowed": false,
+ "followed": false,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "User not found"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/users/{id}/following": {
+ "get": {
+ "operationId": "UsersController_getUserFollowing",
+ "summary": "Get users followed by user",
+ "description": "Retrieve a paginated list of users that the specified user follows. Includes follow relationship to the viewer if authenticated.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the user",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Results per page (default: 10)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "List of followed users with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UsersSearchResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "isFollowed": false,
+ "followed": false,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "User not found"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/admins-access": {
+ "post": {
+ "operationId": "RoomsController_adminsAccess",
+ "summary": "Update room admin access",
+ "description": "Grant or revoke admin privileges for a user in a room. Only room owners or existing admins can modify admin access.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Contains roomId, userId, and admin boolean to grant/revoke access",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomAdminUpdateDto"
+ },
+ "example": {
+ "roomId": 1,
+ "userId": "string",
+ "admin": true
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Admin access updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "success": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to modify admin access"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/groups": {
+ "patch": {
+ "operationId": "RoomsController_updateGroup",
+ "summary": "Update a group",
+ "description": "Update group properties like name, description, URL, avatar, country, or public visibility. Only group admins/owners can update.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Group fields to update - all fields optional except id",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdateGroupDto"
+ },
+ "example": {
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "url": "string",
+ "removeAvatar": true,
+ "avatar": "string",
+ "country": "string",
+ "public": null
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Group updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ },
+ "room": {
+ "type": "object"
+ }
+ }
+ },
+ "example": {
+ "success": true,
+ "room": {}
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to update this group"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "post": {
+ "operationId": "RoomsController_createNewGroup",
+ "summary": "Create a new group",
+ "description": "Create a new community group for sharing reflections. Groups can be public or private, and the creator becomes the owner.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Group creation details including name, description, URL, and visibility",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateGroupDto"
+ },
+ "example": {
+ "name": "string",
+ "description": "string",
+ "url": "string",
+ "public": true
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Group created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomCreatedResponseDto"
+ },
+ "example": {
+ "success": true,
+ "data": {
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid group data or URL already taken"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/pages": {
+ "patch": {
+ "operationId": "RoomsController_updatePage",
+ "summary": "Update a page",
+ "description": "Update page properties like name, description, contact info, organization details, or visibility. Only page admins/owners can update.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Page fields to update - all fields optional except id",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdatePageDto"
+ },
+ "example": {
+ "id": 1,
+ "removeAvatar": true,
+ "avatar": "string",
+ "public": null,
+ "name": "string",
+ "description": "string",
+ "organizationWebsite": "string",
+ "country": "string",
+ "url": "string"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Page updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ },
+ "room": {
+ "type": "object"
+ }
+ }
+ },
+ "example": {
+ "success": true,
+ "room": {}
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to update this page"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "post": {
+ "operationId": "RoomsController_createNewPage",
+ "summary": "Create a new page",
+ "description": "Submit a request to create a new organizational page. Pages require admin approval and include organization details, contact info, and purpose statement.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Page creation details including name, description, URL, organization info, and purpose",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreatePageDto"
+ },
+ "example": {
+ "name": "string",
+ "description": "string",
+ "jobTitle": "string",
+ "contactNumber": "string",
+ "organizationName": "string",
+ "organizationWebsite": "string",
+ "purpose": "string",
+ "additionalDetails": "string",
+ "country": "string",
+ "url": "string",
+ "public": true
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Page request submitted for admin review",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ },
+ "data": {
+ "type": "object"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+ },
+ "example": {
+ "success": true,
+ "data": {},
+ "message": "string"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid page data or URL already taken"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/members": {
+ "get": {
+ "operationId": "RoomsController_getRoomMembers",
+ "summary": "Get room members",
+ "description": "Retrieve paginated list of members in a room (group or page). Returns user profiles with their roles.",
+ "parameters": [
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Members per page (default: 10)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Room members retrieved with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomMembersResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "id": "user-1",
+ "username": "member.username",
+ "firstName": "Member",
+ "lastName": "User",
+ "verified": true,
+ "avatarUrls": {
+ "small": "https://avatars.quran.foundation/users/user-1/small.png",
+ "medium": "https://avatars.quran.foundation/users/user-1/medium.png",
+ "large": "https://avatars.quran.foundation/users/user-1/large.png"
+ },
+ "isAdmin": false,
+ "isOwner": false,
+ "isFollowed": true,
+ "isActive": true,
+ "followersCount": 42
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Room not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/invite": {
+ "post": {
+ "operationId": "RoomsController_inviteUserToRoom",
+ "summary": "Invite user to room",
+ "description": "Send an invitation to a user to join the room. User will receive a notification/email with an invite link. Only admins can invite.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "description": "User identification for invitation (email or userId)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/InviteUserDto"
+ },
+ "example": {
+ "userIds": [
+ "string"
+ ],
+ "emails": [
+ "string"
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Invitation sent successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomInviteUserResponseDto"
+ },
+ "example": {
+ "invited": true,
+ "inviteStatus": {
+ "user-123": true,
+ "user-456": "already_a_member"
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to invite members"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/accept-invite": {
+ "get": {
+ "operationId": "RoomsController_acceptInvite",
+ "summary": "Accept room invite",
+ "description": "Accept an invitation to join a room using the token from the invite link. Adds user as member.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "token",
+ "required": true,
+ "in": "query",
+ "description": "Invitation token from invite link",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Invitation accepted - user is now a member",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomInviteAcceptedResponseDto"
+ },
+ "example": {
+ "accepted": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid or expired token"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/reject-invite": {
+ "get": {
+ "operationId": "RoomsController_rejectInvite",
+ "summary": "Reject room invite",
+ "description": "Decline an invitation to join a room. Invalidates the invite token.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "token",
+ "required": true,
+ "in": "query",
+ "description": "Invitation token from invite link",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Invitation rejected",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomInviteRejectedResponseDto"
+ },
+ "example": {
+ "rejected": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid or expired token"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/members/{userId}": {
+ "delete": {
+ "operationId": "RoomsController_removeMember",
+ "summary": "Remove member from room",
+ "description": "Remove a user from a room (group or page). Only admins can remove other members. Users can remove themselves.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "userId",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the user to remove",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Member removed successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean"
+ }
+ }
+ },
+ "example": {
+ "success": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to remove this member"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/joined-rooms": {
+ "get": {
+ "operationId": "RoomsController_getRooms",
+ "summary": "Get joined or managed rooms",
+ "description": "Retrieve rooms the user has joined (joined-rooms) or manages as admin (managed-rooms). Supports search and pagination.",
+ "parameters": [
+ {
+ "name": "query",
+ "required": false,
+ "in": "query",
+ "description": "Search query for room names",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Rooms per page (default: 5)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 5,
+ "default": 5,
+ "type": "number"
+ }
+ },
+ {
+ "name": "sortBy",
+ "required": false,
+ "in": "query",
+ "description": "Sort order (default: NAME_ASC)",
+ "schema": {
+ "enum": [
+ "NAME_ASC",
+ "NAME_DESC",
+ "LATEST_ACTIVITY"
+ ],
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Rooms retrieved with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaginatedRoomsResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/managed-rooms": {
+ "get": {
+ "operationId": "RoomsController_getRooms",
+ "summary": "Get joined or managed rooms",
+ "description": "Retrieve rooms the user has joined (joined-rooms) or manages as admin (managed-rooms). Supports search and pagination.",
+ "parameters": [
+ {
+ "name": "query",
+ "required": false,
+ "in": "query",
+ "description": "Search query for room names",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Rooms per page (default: 5)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 5,
+ "default": 5,
+ "type": "number"
+ }
+ },
+ {
+ "name": "sortBy",
+ "required": false,
+ "in": "query",
+ "description": "Sort order (default: NAME_ASC)",
+ "schema": {
+ "enum": [
+ "NAME_ASC",
+ "NAME_DESC",
+ "LATEST_ACTIVITY"
+ ],
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Rooms retrieved with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaginatedRoomsResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/search": {
+ "get": {
+ "operationId": "RoomsController_searchRooms",
+ "summary": "Search rooms",
+ "description": "Search for public groups and pages by name or description. Results can be filtered by room type.",
+ "parameters": [
+ {
+ "name": "query",
+ "required": false,
+ "in": "query",
+ "description": "Search term for room name/description",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Results per page (default: 10)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "roomType",
+ "required": false,
+ "in": "query",
+ "description": "Filter by room type: GROUP or PAGE",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Matching rooms with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PaginatedRoomsResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/group/{url}": {
+ "get": {
+ "operationId": "RoomsController_getRoomProfile",
+ "summary": "Get room profile by URL or subdomain",
+ "description": "Retrieve a room profile by its unique URL (for groups) or subdomain (for pages). Returns room details, member counts, and relationship status.",
+ "parameters": [
+ {
+ "name": "url",
+ "required": false,
+ "in": "path",
+ "description": "Group URL identifier (lowercase)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "subdomain",
+ "required": false,
+ "in": "path",
+ "description": "Page subdomain identifier (lowercase)",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Room profile with details and membership info",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomProfileResponseDto"
+ },
+ "example": {
+ "privateToken": "private-room-token",
+ "mutualFollowers": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ ],
+ "mutualFollowersCount": 2,
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Room not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/page/{subdomain}": {
+ "get": {
+ "operationId": "RoomsController_getRoomProfile",
+ "summary": "Get room profile by URL or subdomain",
+ "description": "Retrieve a room profile by its unique URL (for groups) or subdomain (for pages). Returns room details, member counts, and relationship status.",
+ "parameters": [
+ {
+ "name": "url",
+ "required": false,
+ "in": "path",
+ "description": "Group URL identifier (lowercase)",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "subdomain",
+ "required": false,
+ "in": "path",
+ "description": "Page subdomain identifier (lowercase)",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Room profile with details and membership info",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomProfileResponseDto"
+ },
+ "example": {
+ "privateToken": "private-room-token",
+ "mutualFollowers": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ ],
+ "mutualFollowersCount": 2,
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Room not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/group/{url}/accept/{token}": {
+ "get": {
+ "operationId": "RoomsController_acceptByPrivateToken",
+ "summary": "Accept room invite by private token",
+ "description": "Accept an invitation using a private room URL with embedded token. Alternative to the /accept-invite endpoint for direct link access.",
+ "parameters": [
+ {
+ "name": "url",
+ "required": false,
+ "in": "path",
+ "description": "Group URL identifier",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "subdomain",
+ "required": false,
+ "in": "path",
+ "description": "Page subdomain identifier",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "token",
+ "required": true,
+ "in": "path",
+ "description": "Private invitation token",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Invitation accepted - user added to room",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomAcceptByPrivateTokenResponseDto"
+ },
+ "example": {
+ "roomId": 42,
+ "success": true,
+ "isNewMember": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid or expired token"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/page/{subdomain}/accept/{token}": {
+ "get": {
+ "operationId": "RoomsController_acceptByPrivateToken",
+ "summary": "Accept room invite by private token",
+ "description": "Accept an invitation using a private room URL with embedded token. Alternative to the /accept-invite endpoint for direct link access.",
+ "parameters": [
+ {
+ "name": "url",
+ "required": false,
+ "in": "path",
+ "description": "Group URL identifier",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "subdomain",
+ "required": false,
+ "in": "path",
+ "description": "Page subdomain identifier",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "token",
+ "required": true,
+ "in": "path",
+ "description": "Private invitation token",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Invitation accepted - user added to room",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomAcceptByPrivateTokenResponseDto"
+ },
+ "example": {
+ "roomId": 42,
+ "success": true,
+ "isNewMember": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid or expired token"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}": {
+ "get": {
+ "operationId": "RoomsController_getRoomProfileById",
+ "summary": "Get room profile by ID",
+ "description": "Retrieve a room profile by its unique numeric ID. Returns room details, member counts, and relationship status for the current user.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Room profile retrieved successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomProfileResponseDto"
+ },
+ "example": {
+ "privateToken": "private-room-token",
+ "mutualFollowers": [
+ {
+ "avatarUrls": {
+ "small": "https://avatars.githubusercontent.com/u/12345678",
+ "medium": "https://avatars.githubusercontent.com/u/12345678",
+ "large": "https://avatars.githubusercontent.com/u/12345678"
+ },
+ "createdAt": "2000-01-21 00:00:00",
+ "joiningYear": 2025,
+ "isPasswordSet": true,
+ "settings": {
+ "ayahLanguages": [
+ 1
+ ],
+ "reflectionLanguages": [
+ 1
+ ]
+ },
+ "username": "string",
+ "id": "string",
+ "verified": false,
+ "postAs": false,
+ "firstName": "string",
+ "lastName": "string",
+ "postsCount": 0,
+ "averageToxicity": 0,
+ "languageId": 1,
+ "banned": false,
+ "memberType": 1,
+ "followersCount": 0,
+ "likesCount": 0,
+ "isAdmin": false,
+ "languageIsoCode": "en",
+ "bio": "string",
+ "country": "string",
+ "followed": true
+ }
+ ],
+ "mutualFollowersCount": 2,
+ "id": 1,
+ "name": "string",
+ "description": "string",
+ "roomType": "string",
+ "isActive": true,
+ "isVerified": true,
+ "isPublic": true,
+ "isOwner": true,
+ "isAdmin": true,
+ "ownerId": "string",
+ "postsCount": 1,
+ "membersCount": 1,
+ "url": "string",
+ "avatarUrls": {
+ "thumb": "string",
+ "original": "string"
+ },
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "isMember": true,
+ "subdomain": "string",
+ "country": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Room not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{id}/posts": {
+ "get": {
+ "operationId": "RoomsController_getRoomPosts",
+ "summary": "Get room posts",
+ "description": "Retrieve paginated posts shared within a room. Supports filtering by tab (REFLECTIONS, DISCUSSIONS) and sorting (LATEST, POPULAR).",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "sortBy",
+ "required": false,
+ "in": "query",
+ "description": "Sort order (default: latest)",
+ "schema": {
+ "enum": [
+ "latest",
+ "popular"
+ ],
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Posts per page (max: 20)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "tab",
+ "required": false,
+ "in": "query",
+ "description": "Filter posts by content type",
+ "schema": {
+ "enum": [
+ "reflections",
+ "saved",
+ "public",
+ "members_only"
+ ],
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Room posts with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Room not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{groupId}/join": {
+ "post": {
+ "operationId": "RoomsController_joinRoom",
+ "summary": "Join a group",
+ "description": "Join a public group as a member. For private groups, an invitation is required. Returns whether the join was successful.",
+ "parameters": [
+ {
+ "name": "groupId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric group ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successfully joined the group",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "joined": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "joined": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "Group is private - invitation required"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{groupId}/leave": {
+ "post": {
+ "operationId": "RoomsController_leaveGroup",
+ "summary": "Leave a group",
+ "description": "Leave a group the user is currently a member of. Owners cannot leave - they must transfer ownership first.",
+ "parameters": [
+ {
+ "name": "groupId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric group ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successfully left the group",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "left": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "left": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "Owner cannot leave - transfer ownership first"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{pageId}/follow": {
+ "post": {
+ "operationId": "RoomsController_followPage",
+ "summary": "Follow a page",
+ "description": "Follow an organizational page to see their posts in your feed. Pages represent verified organizations or scholars.",
+ "parameters": [
+ {
+ "name": "pageId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric page ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successfully followed the page",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "followed": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "followed": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{pageId}/unfollow": {
+ "post": {
+ "operationId": "RoomsController_unfollowPage",
+ "summary": "Unfollow a page",
+ "description": "Stop following a page. Their posts will no longer appear in your personalized feed.",
+ "parameters": [
+ {
+ "name": "pageId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric page ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successfully unfollowed the page",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "unfollowed": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "unfollowed": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/rooms/{roomId}/posts/{postId}/privacy": {
+ "patch": {
+ "operationId": "RoomsController_updatePostPrivacy",
+ "summary": "Update post privacy in room",
+ "description": "Change the visibility of a post within a room. Toggle between public (visible outside room) and private (members only). Only admins can modify.",
+ "parameters": [
+ {
+ "name": "roomId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric room ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "postId",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "description": "Privacy setting with isPublic boolean",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/RoomPostUpdatePrivacyDto"
+ },
+ "example": {
+ "isPublic": true
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Post privacy updated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostSerialized"
+ },
+ "example": {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to modify post privacy"
+ },
+ "404": {
+ "description": "Room or post not found"
+ }
+ },
+ "tags": [
+ "Rooms"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/feed": {
+ "get": {
+ "operationId": "PostsController_feed",
+ "summary": "Get posts feed",
+ "description": "Retrieve a paginated feed of Quran Reflect posts, including reflections and lessons. Supports filtering by authors, tags, Quran references, groups, pages, and post types. Response items include engagement metadata such as `likesCount`, `commentsCount`, and `recentComment` when available. Use the dedicated comment endpoints to retrieve comment objects and totals. For ayah-by-ayah reads, use `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`, and use `filter[postTypeIds]=1` for reflections or `filter[postTypeIds]=2` for lessons.",
+ "parameters": [
+ {
+ "name": "tab",
+ "required": false,
+ "in": "query",
+ "description": "Feed tab type. `feed` shows personalized content, `trending` shows explore, and `following` shows posts from followed users.",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "newest",
+ "latest",
+ "following",
+ "draft",
+ "favorite",
+ "most_popular",
+ "only_room_members",
+ "public",
+ "feed",
+ "trending",
+ "popular"
+ ]
+ }
+ },
+ {
+ "name": "languages",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated list of language IDs to filter posts by reflection language, for example `languages=1,2`.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "example": [
+ 1,
+ 2
+ ]
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number for pagination (default: 1).",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of posts per page (default: 20).",
+ "schema": {
+ "minimum": 1,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "filter[verifiedOnly]",
+ "required": false,
+ "in": "query",
+ "description": "Whether to limit the feed to verified contributors. Public ayah-by-ayah reads typically combine this with indexed reference filters such as `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`.",
+ "schema": {
+ "type": "boolean",
+ "default": false,
+ "example": true
+ }
+ },
+ {
+ "name": "filter[referencesOperator]",
+ "required": false,
+ "in": "query",
+ "description": "Operator applied to multiple Quran reference filters.",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "OR",
+ "AND"
+ ]
+ }
+ },
+ {
+ "name": "filter[tagsOperator]",
+ "required": false,
+ "in": "query",
+ "description": "Operator applied to multiple tag filters.",
+ "schema": {
+ "type": "string",
+ "enum": [
+ "OR",
+ "AND"
+ ]
+ }
+ },
+ {
+ "name": "filter[postTypeIds]",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated Quran Reflect post type IDs. Use `1` for reflections and `2` for lessons.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ },
+ "example": [
+ 1,
+ 2
+ ]
+ }
+ },
+ {
+ "name": "filter[pages]",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated list of page subdomains to include.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "quran-reflections",
+ "khutbahapp"
+ ]
+ }
+ },
+ {
+ "name": "filter[groups]",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated list of group URLs to include.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "my-group",
+ "ramadan-circle"
+ ]
+ }
+ },
+ {
+ "name": "filter[references][0][to]",
+ "required": false,
+ "in": "query",
+ "description": "Ending ayah number for reference filter index `0`. For a single ayah, use the same value as `from`.",
+ "schema": {
+ "type": "number",
+ "minimum": 1,
+ "example": 255
+ }
+ },
+ {
+ "name": "filter[references][0][from]",
+ "required": false,
+ "in": "query",
+ "description": "Starting ayah number for reference filter index `0`. Pair with the matching `chapterId` and `to` values.",
+ "schema": {
+ "type": "number",
+ "minimum": 1,
+ "example": 255
+ }
+ },
+ {
+ "name": "filter[references][0][chapterId]",
+ "required": false,
+ "in": "query",
+ "description": "Reference filter example for index `0`. Use additional indices such as `filter[references][1][chapterId]` for more references.",
+ "schema": {
+ "type": "number",
+ "minimum": 1,
+ "example": 2
+ }
+ },
+ {
+ "name": "filter[tags]",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated list of tag values to include.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "ramadan",
+ "patience"
+ ]
+ }
+ },
+ {
+ "name": "filter[authors]",
+ "required": false,
+ "in": "query",
+ "style": "form",
+ "explode": false,
+ "description": "Comma-separated list of author identifiers to include.",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "user-1",
+ "user-2"
+ ]
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Feed retrieved successfully with paginated posts",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{postId}/related": {
+ "get": {
+ "operationId": "PostsController_getRelatedPosts",
+ "summary": "Get related posts",
+ "description": "Retrieve posts related to a given post by matching its Quran references with OR logic. Results are filtered by language preferences and ordered by popularity, excluding the source post.",
+ "parameters": [
+ {
+ "name": "postId",
+ "required": true,
+ "in": "path",
+ "description": "Source post ID used for related-post matching",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of posts per page (default: 8, max: 8)",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number for pagination (default: 1)",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Related posts retrieved successfully with pagination metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Source post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/my-posts": {
+ "get": {
+ "operationId": "PostsController_getLoggedinUserPosts",
+ "summary": "Get current user posts",
+ "description": "Retrieve posts created by the currently authenticated user. Supports filtering by tab (MY_REFLECTIONS, SAVED, DRAFTS), sorting options, and post type filtering.",
+ "parameters": [
+ {
+ "name": "tab",
+ "required": false,
+ "in": "query",
+ "description": "Profile tab filter (default: my_reflections)",
+ "schema": {
+ "enum": [
+ "my_reflections",
+ "saved",
+ "notes",
+ "mentions"
+ ],
+ "type": "string"
+ }
+ },
+ {
+ "name": "sortBy",
+ "required": false,
+ "in": "query",
+ "description": "Sort order for posts (default: latest)",
+ "schema": {
+ "enum": [
+ "latest",
+ "popular"
+ ],
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of posts per page (default: 20, max: 20)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number for pagination (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "postTypeIds",
+ "required": false,
+ "in": "query",
+ "description": "Array of post type IDs to filter by",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User posts retrieved successfully with pagination metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/liked": {
+ "get": {
+ "operationId": "PostsController_getLikedState",
+ "summary": "Get post liked state",
+ "description": "Returns whether the authenticated user currently likes the post. This lightweight endpoint avoids loading the full post payload for simple like-state checks.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to check liked state for",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Like state retrieved successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "liked": {
+ "type": "boolean",
+ "description": "true when the post is liked by the current user"
+ }
+ }
+ },
+ "example": {
+ "liked": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}": {
+ "get": {
+ "operationId": "PostsController_findOne",
+ "summary": "Get post by ID",
+ "description": "Retrieve a specific post by its unique numeric ID. Returns the full post with author details, tags, references, room information, and engagement metrics. Admins can view additional moderation details.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Post found and returned with all associated data",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostSerialized"
+ },
+ "example": {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Post not found or has been deleted"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "delete": {
+ "operationId": "PostsController_delete",
+ "summary": "Delete post",
+ "description": "Soft-delete a post by marking it as removed. Only the post author or admins can delete posts. Related engagement counts (likes, comments, saves) update asynchronously via background jobs, so metrics may briefly lag.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to delete",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Post deletion accepted and queued for processing",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "success": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to delete this post"
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ },
+ "patch": {
+ "operationId": "PostsController_edit",
+ "summary": "Edit post",
+ "description": "Update an existing post. Only the post author or admins can edit. Supports updating body, references, mentions, draft status, and room visibility settings.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to update",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "description": "Partial post data to update - only include fields to change",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/UpdatePostDto"
+ },
+ "example": {
+ "roomPostStatus": 0,
+ "body": "string",
+ "draft": true,
+ "references": [
+ {
+ "chapterId": 1,
+ "from": 0,
+ "to": 0
+ }
+ ],
+ "mentions": [
+ {
+ "marker": "{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}",
+ "userId": "string",
+ "displayName": "string"
+ }
+ ],
+ "roomId": 1,
+ "postAsAuthorId": "string",
+ "publishedAt": "2026-04-02T00:00:00.000Z"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Post updated successfully with the updated post data",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostCreatedResponse"
+ },
+ "example": {
+ "data": {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ },
+ "success": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "403": {
+ "description": "User not authorized to edit this post"
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/viewed/{id}": {
+ "get": {
+ "operationId": "PostsController_viewTracking",
+ "summary": "Track post view",
+ "description": "Record that a post has been viewed by the current user (if authenticated). Used for analytics and engagement tracking. Does not require authentication but will track user-specific views when logged in.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "View tracked successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "success": true
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts": {
+ "post": {
+ "operationId": "PostsController_create",
+ "summary": "Create post",
+ "description": "Create a new post (reflection) with Quran references. Posts can be public, drafts, or associated with a room (group/page). Supports user mentions and multiple Quran verse references. Minimum body length is 6 characters.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Post creation payload containing the post object with body, references, mentions, and visibility settings",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreatePostBodyDto"
+ },
+ "example": {
+ "post": {
+ "roomPostStatus": 0,
+ "body": "string",
+ "draft": true,
+ "references": [
+ {
+ "chapterId": 1,
+ "from": 0,
+ "to": 0
+ }
+ ],
+ "mentions": [
+ {
+ "marker": "{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}",
+ "userId": "string",
+ "displayName": "string"
+ }
+ ],
+ "roomId": 1,
+ "postAsAuthorId": "string",
+ "publishedAt": "2026-04-02T00:00:00.000Z"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Post created successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostCreatedResponse"
+ },
+ "example": {
+ "data": {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ },
+ "success": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid post data - body too short, invalid references, or invalid room post status"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/report": {
+ "post": {
+ "operationId": "PostsController_reportAbuse",
+ "summary": "Report post abuse",
+ "description": "Report a post for moderation review. Provide a reason for the report to help moderators evaluate the content. Multiple reports on the same post may trigger automatic review.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to report",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "requestBody": {
+ "required": true,
+ "description": "Report details including reason for flagging the content",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ReportAbuseBodyDto"
+ },
+ "example": {
+ "report": {
+ "abuse": "string",
+ "comments": ""
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Report submitted successfully for moderation review",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "reported": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "reported": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/user-posts/{id}": {
+ "get": {
+ "operationId": "PostsController_getUserPost",
+ "summary": "Get user posts",
+ "description": "Retrieve public posts created by a specific user. If viewing own posts while authenticated, returns all posts including drafts. Supports sorting and filtering by post type.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "UUID of the user whose posts to retrieve",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "sortBy",
+ "required": false,
+ "in": "query",
+ "description": "Sort order for posts (default: latest)",
+ "schema": {
+ "enum": [
+ "latest",
+ "popular"
+ ],
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of posts per page (default: 20, max: 20)",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number for pagination (default: 1)",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ },
+ {
+ "name": "postTypeIds",
+ "required": false,
+ "in": "query",
+ "description": "Array of post type IDs to filter by",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User posts retrieved with pagination metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/toggle-like": {
+ "post": {
+ "operationId": "PostsController_toggleLike",
+ "summary": "Toggle post like",
+ "description": "Toggle like status for a post. If already liked, removes the like. If not liked, adds a like. Updates the post like count and triggers notifications.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to like/unlike",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Like status toggled - returns new state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "liked": {
+ "type": "boolean",
+ "description": "true if now liked, false if now unliked"
+ }
+ }
+ },
+ "example": {
+ "liked": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/toggle-save": {
+ "post": {
+ "operationId": "PostsController_toggleSave",
+ "summary": "Toggle post save",
+ "description": "Toggle save/bookmark status for a post. Saved posts appear in the SAVED tab of the user profile for easy access later.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID to save/unsave",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Save status toggled - returns new state",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "saved": {
+ "type": "boolean",
+ "description": "true if now saved, false if now unsaved"
+ }
+ }
+ },
+ "example": {
+ "saved": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/comments": {
+ "get": {
+ "operationId": "PostsController_getComments",
+ "summary": "Get post comments",
+ "description": "Retrieve paginated top-level comments for a post. Use the replies endpoint to get nested replies for specific comments.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of results to return",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Comments retrieved with pagination metadata",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostCommentsResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "comments": [
+ {
+ "id": 1,
+ "postId": 1,
+ "authorId": "string",
+ "parentId": 1,
+ "isPrivate": false,
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "toxicityScore": 1,
+ "repliesCount": 0,
+ "likesCount": 0,
+ "reported": false,
+ "removed": false,
+ "hidden": false,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string",
+ "commentsCount": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/{id}/all-comments": {
+ "get": {
+ "operationId": "PostsController_getAllComment",
+ "summary": "Get all post comments",
+ "description": "Retrieve all comments for a post in a single request without pagination. Useful for displaying full comment threads or export scenarios.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric post ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "All comments returned with total count",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/PostAllCommentsResponse"
+ },
+ "example": {
+ "comments": [
+ {
+ "id": 1,
+ "postId": 1,
+ "authorId": "string",
+ "parentId": 1,
+ "isPrivate": false,
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "toxicityScore": 1,
+ "repliesCount": 0,
+ "likesCount": 0,
+ "reported": false,
+ "removed": false,
+ "hidden": false,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string",
+ "commentsCount": 1
+ }
+ ]
+ }
+ ],
+ "total": "10 // works also with swagger setup"
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Post not found"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/export/pdf": {
+ "post": {
+ "operationId": "PostsController_exportMultiplePosts",
+ "summary": "Export posts as PDF",
+ "description": "Generate a downloadable PDF document containing selected posts with their full content, Quran references, and author information. Ayah translations are rendered according to user language preferences.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Array of post IDs to include in the PDF export (minimum 1)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/ExportPostsDto"
+ },
+ "example": {
+ "ids": [
+ 1,
+ 2,
+ 3
+ ]
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "PDF file generated and returned as binary attachment",
+ "content": {
+ "application/pdf": {
+ "schema": {
+ "type": "string",
+ "format": "binary"
+ },
+ "example": "string"
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid request - empty or invalid post IDs array"
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "No accessible posts found for the given IDs"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/count-within-range": {
+ "get": {
+ "operationId": "PostsController_getMyPostsCountWithinRange",
+ "summary": "Get posts count within range",
+ "description": "Count how many posts the current user has written for verses within a specified Quran verse range. Useful for reading goals and progress tracking.",
+ "parameters": [
+ {
+ "name": "from",
+ "required": true,
+ "in": "query",
+ "description": "Start verse key in format chapter:verse (e.g., \"2:1\")",
+ "schema": {
+ "pattern": "VERSE_KEY_REGEX",
+ "example": "2:1",
+ "type": "string"
+ }
+ },
+ {
+ "name": "to",
+ "required": true,
+ "in": "query",
+ "description": "End verse key in format chapter:verse (e.g., \"2:286\")",
+ "schema": {
+ "pattern": "VERSE_KEY_REGEX",
+ "example": "2:286",
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Count of posts within the specified verse range",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "number",
+ "example": 5
+ }
+ }
+ },
+ "example": {
+ "count": 5
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid verse range - malformed keys or from > to"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/posts/by-verse/{verseKey}": {
+ "get": {
+ "operationId": "PostsController_getMyPostsByVerse",
+ "summary": "Get posts by verse",
+ "description": "Retrieve all posts written by the current user for a specific Quran verse. This endpoint requires a user-bound token and returns only the authenticated user's own posts. It is not part of the public `client_credentials`-compatible read subset; for public ayah-by-ayah reads, use `GET /v1/posts/feed` with indexed reference filters such as `filter[references][0][chapterId]`, `filter[references][0][from]`, and `filter[references][0][to]`.",
+ "parameters": [
+ {
+ "name": "verseKey",
+ "required": true,
+ "in": "path",
+ "description": "Verse key in format chapter:verse",
+ "schema": {
+ "pattern": "VERSE_KEY_REGEX",
+ "example": "2:255",
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "User posts for the specified verse",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/FeedResponseDto"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "data": [
+ {
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string"
+ }
+ ],
+ "references": [
+ {
+ "id": "string",
+ "from": 1,
+ "to": 1,
+ "chapterId": 1
+ }
+ ],
+ "author": {},
+ "recentComment": {
+ "id": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z"
+ },
+ "room": {
+ "isAdmin": {},
+ "isOwner": {},
+ "isPublic": {},
+ "id": 1,
+ "subdomain": "string",
+ "roomType": "string",
+ "verified": false,
+ "name": "string",
+ "_group": "string"
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "isLiked": true,
+ "isByFollowedUser": true,
+ "isCommentedOn": true,
+ "isSaved": true,
+ "id": 1,
+ "authorId": "string",
+ "body": "string",
+ "discussionId": 1,
+ "draft": false,
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "publishedAt": "2026-04-02T00:00:00.000Z",
+ "global": true,
+ "toxicityScore": 1,
+ "reported": false,
+ "views": 1,
+ "removed": false,
+ "verified": false,
+ "roomPostStatus": 0,
+ "hidden": false,
+ "commentsCount": 0,
+ "likesCount": 0,
+ "viewsCount": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "reviewedAt": "2026-04-02T00:00:00.000Z",
+ "featuredAt": "2026-04-02T00:00:00.000Z",
+ "estimatedReadingTime": 0,
+ "roomId": 1,
+ "postTypeId": 1,
+ "postTypeName": "string"
+ }
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid verse key format"
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Posts"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/tags": {
+ "get": {
+ "operationId": "TagsController_find",
+ "summary": "Search and retrieve tags",
+ "description": "Search for tags by query string. Returns paginated results matching the search term. Useful for tag autocomplete and discovery features.",
+ "parameters": [
+ {
+ "name": "query",
+ "required": false,
+ "in": "query",
+ "description": "Search term",
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of results to return",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Tags matching search query with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Tag"
+ }
+ },
+ "example": [
+ {
+ "id": 1,
+ "name": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "rank": 0,
+ "languageId": 1,
+ "languageName": "string",
+ "postsCount": 1,
+ "commentsCount": 1
+ }
+ ]
+ }
+ }
+ }
+ },
+ "tags": [
+ "Tags"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/comments": {
+ "post": {
+ "operationId": "CommentsController_create",
+ "summary": "Create a new comment",
+ "description": "Add a comment to a post or reply to an existing comment. Supports mentions and notifies the post author.",
+ "parameters": [],
+ "requestBody": {
+ "required": true,
+ "description": "Comment with postId and optional parentId",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateCommentBody"
+ },
+ "example": {
+ "comment": {
+ "body": "This is a thoughtful comment about the post",
+ "postId": 123,
+ "isPrivate": false,
+ "parentId": 456,
+ "mentions": [
+ {
+ "marker": "{{9e639c0f-e02f-c32f-b0ae-e0d8c8d80b2d}}",
+ "userId": "string",
+ "displayName": "string"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "201": {
+ "description": "Comment created",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CreateCommentResponse"
+ },
+ "example": {
+ "comment": {
+ "id": 1,
+ "postId": 1,
+ "authorId": "string",
+ "parentId": 1,
+ "isPrivate": false,
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "toxicityScore": 1,
+ "repliesCount": 0,
+ "likesCount": 0,
+ "reported": false,
+ "removed": false,
+ "hidden": false,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string",
+ "commentsCount": 1
+ }
+ ]
+ },
+ "success": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Invalid comment - empty body or invalid postId"
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "Post or parent comment not found"
+ }
+ },
+ "tags": [
+ "Comments"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/comments/{id}/delete": {
+ "get": {
+ "operationId": "CommentsController_deleteComment",
+ "summary": "Delete a comment",
+ "description": "Soft-delete a comment and its direct replies. Only the comment owner, post owner, or admins can delete.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric comment ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Comment deleted",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "removed": {
+ "type": "boolean",
+ "example": true
+ }
+ }
+ },
+ "example": {
+ "removed": true
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "User not authorized to delete this comment"
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "The comment has already been deleted"
+ }
+ },
+ "tags": [
+ "Comments"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/comments/{id}/toggle-like": {
+ "post": {
+ "operationId": "CommentsController_toggleLike",
+ "summary": "Toggle like/unlike a comment",
+ "description": "Toggle like status. If liked, removes like. Notifies comment author on new likes.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Unique numeric comment ID",
+ "schema": {
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Like toggled",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "liked": {
+ "type": "boolean",
+ "description": "true if liked, false if unliked"
+ }
+ }
+ },
+ "example": {
+ "liked": true
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ },
+ "404": {
+ "description": "Comment not found"
+ }
+ },
+ "tags": [
+ "Comments"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/comments/{id}/replies": {
+ "get": {
+ "operationId": "CommentsController_get",
+ "summary": "Get replies to a comment",
+ "description": "Retrieve paginated replies (nested comments) for a parent comment with author info.",
+ "parameters": [
+ {
+ "name": "id",
+ "required": true,
+ "in": "path",
+ "description": "Parent comment ID",
+ "schema": {
+ "type": "number"
+ }
+ },
+ {
+ "name": "limit",
+ "required": false,
+ "in": "query",
+ "description": "Number of results to return",
+ "schema": {
+ "minimum": 1,
+ "maximum": 20,
+ "default": 20,
+ "type": "number"
+ }
+ },
+ {
+ "name": "page",
+ "required": false,
+ "in": "query",
+ "description": "Page number",
+ "schema": {
+ "minimum": 1,
+ "default": 1,
+ "type": "number"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Comment replies with pagination",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/CommentRepliesResponse"
+ },
+ "example": {
+ "total": 10,
+ "currentPage": 1,
+ "limit": 10,
+ "pages": 1,
+ "replies": [
+ {
+ "id": 1,
+ "postId": 1,
+ "authorId": "string",
+ "parentId": 1,
+ "isPrivate": false,
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "toxicityScore": 1,
+ "repliesCount": 0,
+ "likesCount": 0,
+ "reported": false,
+ "removed": false,
+ "hidden": false,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string",
+ "commentsCount": 1
+ }
+ ]
+ }
+ ],
+ "comment": {
+ "id": 1,
+ "postId": 1,
+ "authorId": "string",
+ "parentId": 1,
+ "isPrivate": false,
+ "body": "string",
+ "createdAt": "2026-04-02T00:00:00.000Z",
+ "updatedAt": "2026-04-02T00:00:00.000Z",
+ "toxicityScore": 1,
+ "repliesCount": 0,
+ "likesCount": 0,
+ "reported": false,
+ "removed": false,
+ "hidden": false,
+ "languageId": 1,
+ "languageName": "string",
+ "moderationStatus": 1,
+ "author": {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1
+ },
+ "mentions": [
+ {
+ "postsCount": 1,
+ "avatarUrls": {
+ "small": "string",
+ "medium": "string",
+ "large": "string"
+ },
+ "id": "string",
+ "username": "string",
+ "verified": false,
+ "firstName": "string",
+ "lastName": "string",
+ "memberType": 1,
+ "locations": {},
+ "followersCount": 1,
+ "displayName": "string"
+ }
+ ],
+ "tags": [
+ {
+ "language": "string",
+ "id": 1,
+ "name": "string",
+ "commentsCount": 1
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Parent comment not found"
+ }
+ },
+ "tags": [
+ "Comments"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ },
+ "/v1/sync": {
+ "get": {
+ "description": "Get list of mutations that were applied to resources after a certain point in time.",
+ "tags": [
+ "Sync"
+ ],
+ "summary": "Get mutations",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "mutationsSince",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp to get mutations since.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp to get mutations since."
+ },
+ {
+ "in": "query",
+ "name": "resources",
+ "schema": {
+ "type": "string",
+ "description": "Comma-separated list of resources to filter mutations by (e.g. \"BOOKMARK,COLLECTION,COLLECTION_BOOKMARK,NOTE\"). If not provided, all accessible resources will be returned.",
+ "example": "BOOKMARK,COLLECTION,COLLECTION_BOOKMARK"
+ },
+ "required": false,
+ "description": "Comma-separated list of resources to filter mutations by (e.g. \"BOOKMARK,COLLECTION,COLLECTION_BOOKMARK,NOTE\"). If not provided, all accessible resources will be returned."
+ },
+ {
+ "in": "query",
+ "name": "metadataOnly",
+ "schema": {
+ "type": "boolean",
+ "description": "When true, returns only the lastMutationAt timestamp without fetching actual mutations. This is significantly faster (single DB query vs multiple joins) and ideal for: 1) Checking if new data exists before performing a full sync, 2) Implementing periodic background polling to detect changes, 3) Recovering the current lastMutationAt if the client missed the X-Mutation-At header from a previous successful mutation response. Response will only contain { lastMutationAt: number }.",
+ "example": true,
+ "default": false
+ },
+ "required": false,
+ "description": "When true, returns only the lastMutationAt timestamp without fetching actual mutations. This is significantly faster (single DB query vs multiple joins) and ideal for: 1) Checking if new data exists before performing a full sync, 2) Implementing periodic background polling to detect changes, 3) Recovering the current lastMutationAt if the client missed the X-Mutation-At header from a previous successful mutation response. Response will only contain { lastMutationAt: number }."
+ },
+ {
+ "in": "query",
+ "name": "limit",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "minimum": 1,
+ "maximum": 1000,
+ "description": "Maximum number of mutations to return per page (1-1000).",
+ "example": 100,
+ "default": 100
+ },
+ "required": false,
+ "description": "Maximum number of mutations to return per page (1-1000)."
+ },
+ {
+ "in": "query",
+ "name": "page",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "minimum": 1,
+ "description": "Page number (1-based).",
+ "example": 1,
+ "default": 1
+ },
+ "required": false,
+ "description": "Page number (1-based)."
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "mutations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "CREATE",
+ "UPDATE",
+ "DELETE"
+ ],
+ "description": "The type of the mutation",
+ "example": "CREATE"
+ },
+ "resource": {
+ "type": "string",
+ "enum": [
+ "BOOKMARK",
+ "COLLECTION",
+ "COLLECTION_BOOKMARK",
+ "NOTE"
+ ],
+ "description": "The resource the mutation was applied to.",
+ "example": "BOOKMARK"
+ },
+ "resourceId": {
+ "type": "string",
+ "description": "The id of the resource the mutation was applied to. Will not be present for resources that use composite keys (e.g. COLLECTION_BOOKMARK uses data.collection and data.bookmark instead).",
+ "example": "lqc794i0qnxq4pdlfanfbd2r"
+ },
+ "data": {
+ "type": "object",
+ "properties": {},
+ "description": "The latest version of the data of the resource that was mutated. Will be empty when the mutation is a delete.",
+ "example": {
+ "bookmarkType": "ayah",
+ "bookmarkGroup": "verses_6236",
+ "key": 6,
+ "verseNumber": 3
+ }
+ },
+ "timestamp": {
+ "type": "number",
+ "format": "float",
+ "description": "Unix timestamp when the latest mutation of the resource occurred",
+ "example": 1731636500303
+ }
+ },
+ "required": [
+ "type",
+ "resource",
+ "timestamp"
+ ],
+ "additionalProperties": false,
+ "description": "Represents a single mutation/change to a resource"
+ },
+ "description": "Array of mutations that occurred after lastMutationAt. Will be omitted when metadataOnly is set to true.",
+ "example": [
+ {
+ "type": "CREATE",
+ "resource": "BOOKMARK",
+ "resourceId": "u54maufl0ftmarp73ei0hg64",
+ "data": {
+ "bookmarkType": "ayah",
+ "bookmarkGroup": "verses_6236",
+ "key": 6,
+ "verseNumber": 3
+ },
+ "timestamp": 1769340915572
+ },
+ {
+ "type": "UPDATE",
+ "resource": "COLLECTION",
+ "resourceId": "na6orcv0pbcomiphmkv0yhma",
+ "data": {
+ "name": "New collection!",
+ "slug": "new-collection",
+ "isPrivate": true
+ },
+ "timestamp": 1769340915572
+ },
+ {
+ "type": "CREATE",
+ "resource": "COLLECTION_BOOKMARK",
+ "data": {
+ "collection": "na6orcv0pbcomiphmkv0yhma",
+ "bookmark": "u54maufl0ftmarp73ei0hg64"
+ },
+ "timestamp": 1769340915575
+ },
+ {
+ "type": "DELETE",
+ "resource": "NOTE",
+ "resourceId": "his2lubkxxr3l102nqptmnur",
+ "data": {},
+ "timestamp": 1769341113173
+ }
+ ]
+ },
+ "page": {
+ "type": "number",
+ "format": "float",
+ "description": "Current page number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "format": "float",
+ "description": "Items per page",
+ "example": 100
+ },
+ "total": {
+ "type": "number",
+ "format": "float",
+ "description": "Total number of mutations",
+ "example": 150
+ },
+ "hasMore": {
+ "type": "boolean",
+ "description": "Whether more pages exist",
+ "example": true
+ },
+ "lastMutationAt": {
+ "type": "number",
+ "format": "float",
+ "description": "Timestamp of the latest mutation. This should be used for subsequent sync requests. If metadataOnly is true, this will be the only field returned.",
+ "example": 1731636500303
+ }
+ },
+ "required": [
+ "lastMutationAt"
+ ],
+ "additionalProperties": false,
+ "description": "Response schema for get mutations endpoint"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params. Please check the request params and try again.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request was well-formed but was unable to be followed due to semantic errors"
+ },
+ "type": {
+ "type": "string",
+ "example": "unprocessable_entity"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ }
+ },
+ "post": {
+ "description": "An endpoint to sync local mutations to the server.",
+ "tags": [
+ "Sync"
+ ],
+ "summary": "Sync local mutations",
+ "parameters": [
+ {
+ "in": "query",
+ "name": "lastMutationAt",
+ "schema": {
+ "type": "number",
+ "format": "float",
+ "description": "The timestamp of the last mutation that was applied on the server. The value needs to match the latest value from get mutations endpoint, otherwise, the request will be rejected.",
+ "example": 1731636500303
+ },
+ "required": true,
+ "description": "The timestamp of the last mutation that was applied on the server. The value needs to match the latest value from get mutations endpoint, otherwise, the request will be rejected."
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "mutations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "CREATE",
+ "UPDATE",
+ "DELETE"
+ ],
+ "description": "The type of the mutation",
+ "example": "CREATE"
+ },
+ "resource": {
+ "type": "string",
+ "enum": [
+ "BOOKMARK",
+ "COLLECTION",
+ "COLLECTION_BOOKMARK",
+ "NOTE"
+ ],
+ "description": "Resource the mutation applies to.",
+ "example": "BOOKMARK"
+ },
+ "resourceId": {
+ "type": "string",
+ "description": "Server's ID for finding the resource during update/delete operations.",
+ "example": "lqc794i0qnxq4pdlfanfbd2r"
+ },
+ "data": {
+ "type": "object",
+ "properties": {},
+ "description": "Resource data. Format depends on resource type.",
+ "example": {
+ "bookmarkType": "ayah",
+ "bookmarkGroup": "verses_6236",
+ "key": 6,
+ "verseNumber": 3
+ }
+ }
+ },
+ "required": [
+ "type",
+ "resource"
+ ],
+ "additionalProperties": false,
+ "description": "Represents a single mutation/change to a resource"
+ }
+ }
+ },
+ "required": [
+ "mutations"
+ ],
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "Request has been handled successfully.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "data": {
+ "type": "object",
+ "properties": {
+ "mutations": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "enum": [
+ "CREATE",
+ "UPDATE",
+ "DELETE"
+ ],
+ "description": "The type of the mutation",
+ "example": "CREATE"
+ },
+ "resource": {
+ "type": "string",
+ "enum": [
+ "BOOKMARK",
+ "COLLECTION",
+ "COLLECTION_BOOKMARK",
+ "NOTE"
+ ],
+ "description": "The resource the mutation was applied to.",
+ "example": "BOOKMARK"
+ },
+ "resourceId": {
+ "type": "string",
+ "description": "The id of the resource the mutation was applied to. Will not be present for resources that use composite keys (e.g. COLLECTION_BOOKMARK uses data.collection and data.bookmark instead).",
+ "example": "lqc794i0qnxq4pdlfanfbd2r"
+ },
+ "data": {
+ "type": "object",
+ "properties": {},
+ "description": "The latest version of the data of the resource that was mutated. Will be empty when the mutation is a delete.",
+ "example": {
+ "bookmarkType": "ayah",
+ "bookmarkGroup": "verses_6236",
+ "key": 6,
+ "verseNumber": 3
+ }
+ },
+ "timestamp": {
+ "type": "number",
+ "format": "float",
+ "description": "Unix timestamp when the latest mutation of the resource occurred",
+ "example": 1731636500303
+ }
+ },
+ "required": [
+ "type",
+ "resource",
+ "timestamp"
+ ],
+ "additionalProperties": false,
+ "description": "Represents a single mutation/change to a resource"
+ },
+ "description": "Array of mutations that were successfully applied on the server.",
+ "example": [
+ {
+ "type": "CREATE",
+ "resource": "BOOKMARK",
+ "resourceId": "u54maufl0ftmarp73ei0hg64",
+ "data": {
+ "bookmarkType": "ayah",
+ "bookmarkGroup": "verses_6236",
+ "key": 6,
+ "verseNumber": 3
+ },
+ "timestamp": 1769340915572
+ },
+ {
+ "type": "UPDATE",
+ "resource": "COLLECTION",
+ "resourceId": "na6orcv0pbcomiphmkv0yhma",
+ "data": {
+ "name": "New collection!",
+ "slug": "new-collection",
+ "isPrivate": true
+ },
+ "timestamp": 1769340915572
+ },
+ {
+ "type": "CREATE",
+ "resource": "COLLECTION_BOOKMARK",
+ "data": {
+ "collection": "na6orcv0pbcomiphmkv0yhma",
+ "bookmark": "u54maufl0ftmarp73ei0hg64"
+ },
+ "timestamp": 1769340915575
+ },
+ {
+ "type": "DELETE",
+ "resource": "NOTE",
+ "resourceId": "his2lubkxxr3l102nqptmnur",
+ "data": {},
+ "timestamp": 1769341113173
+ }
+ ]
+ },
+ "page": {
+ "type": "number",
+ "format": "float",
+ "description": "Current page number",
+ "example": 1
+ },
+ "limit": {
+ "type": "number",
+ "format": "float",
+ "description": "Items per page",
+ "example": 100
+ },
+ "total": {
+ "type": "number",
+ "format": "float",
+ "description": "Total number of mutations",
+ "example": 150
+ },
+ "hasMore": {
+ "type": "boolean",
+ "description": "Whether more pages exist",
+ "example": true
+ },
+ "lastMutationAt": {
+ "type": "number",
+ "format": "float",
+ "description": "Timestamp of the latest mutation that was applied on the server. This should be used for subsequent sync requests.",
+ "example": 1731636500303
+ }
+ },
+ "required": [
+ "lastMutationAt"
+ ],
+ "additionalProperties": false,
+ "description": "Response schema for post mutations endpoint"
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ },
+ "headers": {
+ "X-Mutation-At": {
+ "description": "Unix timestamp (milliseconds) of the latest mutation for the user. Clients should store this value and include it in subsequent mutation requests for optimistic concurrency control.",
+ "schema": {
+ "type": "string",
+ "example": "1731636500303"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "The request is missing required parameters or is invalid.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request is missing required headers or is invalid"
+ },
+ "type": {
+ "type": "string",
+ "example": "invalid_request"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request is unauthorized.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The request requires user authentication"
+ },
+ "type": {
+ "type": "string",
+ "example": "unauthorized"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Forbidden error. Can either be due to access token not being passed, having been expired or the caller trying to access a resource without enough permissions.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server understood the request, but refuses to authorize it"
+ },
+ "type": {
+ "type": "string",
+ "example": "forbidden"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Not Found. The resource being accessed does not exist.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The requested resource could not be found"
+ },
+ "type": {
+ "type": "string",
+ "example": "not_found"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "409": {
+ "description": "Out of Sync Error. The client lastMutationAt does not match server state. Client must re-sync data before retrying this operation.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "OutOfSyncError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Out of sync": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "Invalid lastMutationAt, please re-sync your data and try again."
+ }
+ }
+ },
+ "First sync - wrong lastMutationAt": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "OutOfSyncError",
+ "message": "First sync detected. Please use lastMutationAt=-1 for initial sync."
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error. The request includes one or more invalid params.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": false
+ },
+ "error": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string",
+ "example": "ValidationError"
+ },
+ "message": {
+ "type": "string",
+ "example": "Invalid mutations"
+ }
+ }
+ }
+ }
+ },
+ "examples": {
+ "Invalid mutations format": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Invalid mutations"
+ }
+ }
+ },
+ "Too many mutations": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Mutations must not exceed 100"
+ }
+ }
+ },
+ "Missing resource": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Missing resource at mutation[0]"
+ }
+ }
+ },
+ "Invalid resource": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Invalid resource: \"invalidResource\" at mutation[0]"
+ }
+ }
+ },
+ "Missing mutation type": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Missing mutation type at mutation[0]"
+ }
+ }
+ },
+ "Invalid mutation type": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Invalid mutation type: \"invalidType\" at mutation[0]"
+ }
+ }
+ },
+ "Missing resourceId": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Missing resourceId at mutation[0]"
+ }
+ }
+ },
+ "Invalid resourceId type": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Invalid resourceId at mutation[0]"
+ }
+ }
+ },
+ "Missing data": {
+ "value": {
+ "success": false,
+ "error": {
+ "code": "ValidationError",
+ "message": "Missing data at mutation[0]"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "429": {
+ "description": "Too many requests, please try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "Too many requests, please try again later"
+ },
+ "type": {
+ "type": "string",
+ "example": "rate_limit_exceeded"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "500": {
+ "description": "Server Error. Something went wrong, try again later.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server encountered an internal error and was unable to complete your request"
+ },
+ "type": {
+ "type": "string",
+ "example": "internal_server_error"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "502": {
+ "description": "Invalid response from the upstream server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and received an invalid response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "bad_gateway"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "503": {
+ "description": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server is currently unable to handle the request due to a temporary overload or scheduled maintenance"
+ },
+ "type": {
+ "type": "string",
+ "example": "service_unavailable"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ },
+ "504": {
+ "description": "The server did not receive a timely response from the upstream server.",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "type": "string",
+ "example": "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server"
+ },
+ "type": {
+ "type": "string",
+ "example": "gateway_timeout"
+ },
+ "success": {
+ "type": "boolean",
+ "example": false
+ }
+ },
+ "additionalProperties": false
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/v1/users": {
+ "delete": {
+ "operationId": "UsersController_deleteAccount",
+ "summary": "Delete user account permanently",
+ "description": "Permanently delete the authenticated user account and all associated data from QuranReflect and Quran.com. This action is irreversible. The user is immediately banned to prevent further actions, then all data is deleted in the background. All posts, comments, likes, preferences, and memberships will be removed. If the user owns rooms, posts by other members will be converted to global posts.",
+ "parameters": [],
+ "responses": {
+ "200": {
+ "description": "Account deletion initiated successfully",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "boolean",
+ "example": true
+ },
+ "message": {
+ "type": "string",
+ "example": "Account deletion initiated successfully"
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "User not authenticated"
+ }
+ },
+ "tags": [
+ "Users"
+ ],
+ "servers": [
+ {
+ "url": "https://apis-prelive.quran.foundation/quran-reflect",
+ "description": "Pre-production Server"
+ },
+ {
+ "url": "https://apis.quran.foundation/quran-reflect",
+ "description": "Production Server"
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/sidebars.js b/sidebars.js
index 5c10c0e0..dff88f2e 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -466,6 +466,7 @@ const buildTutorialsSidebarItems = () => [
collapsed: false,
items: [
"tutorials/oidc/getting-started-with-oauth2",
+ "tutorials/oidc/user-apis-quickstart",
"tutorials/oidc/openid-connect",
"tutorials/oidc/example-integration",
"tutorials/oidc/client-setup",
@@ -580,6 +581,7 @@ const sidebars = {
],
tutorialsSidebar: [
+ "tutorials/faq",
...buildTutorialsSidebarItems(),
],