Ramadan Last 10 Nights Campaign

Used by thousands of students worldwide - help us reach 150 members

... / 150 members...
APICommunity

Community

/community

Social feed: posts with image/video media, one-level threaded comments, likes, content reports, user profiles and follows. Every route in this group requires a logged-in user. Authentication failures are answered by the auth middleware with plain-text bodies (401 no token, 403 invalid token or missing role, 404 when the token's user no longer exists).

POST/community/posts

Create a post

Auth required

Creates a community post, optionally with up to 10 media attachments. Each attachment is uploaded to S3; videos also get a 320x180 JPEG thumbnail generated with ffmpeg (if thumbnail generation fails the post is still created without `thumbnailKey`). All followers of the author are sent a `new_post` notification (fire-and-forget). The response contains the stored media keys but no presigned media URLs — fetch the post or feed to get `url` / `thumbnailUrl`. The author's `profilePicture` is replaced by a 1-hour presigned URL when the author has an uploaded picture (`profilePictureKey`).

Send the body as multipart/form-data.

Body parameters

contentrequired
string
Post body (rich content as produced by the client editor).
contentPlainText
string
Plain-text version of the content (text-indexed on the server).Default: ''
media
file[]
Up to 10 files under the field name `media`. Allowed MIME types: image/jpeg, image/png, image/gif, image/webp, video/mp4, video/quicktime. Max 100 MB per file.

Errors

  • 400`content` is missing
  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 500Upload/S3/database failure. A rejected file (disallowed MIME type, file over 100 MB, more than 10 files) is also answered with a plain-text 500 by the global error handler.
Request
curl -X POST "https://app.ummahspot.com/community/posts" \
  -H "Authorization: Bearer $SHARH_TOKEN" \
  -F "content=value" \
  -F "media=@/path/to/file"
Response · 201
{
  "post": {
    "_id": "66f1a2b3c4d5e6f708192a3b",
    "author": {
      "_id": "64d0f1e2a3b4c5d6e7f80910",
      "username": "abdullah",
      "profilePicture": "https://bucket.s3.amazonaws.com/profile-pictures/abc.jpg?X-Amz-Signature=...",
      "profilePictureKey": "profile-pictures/abc.jpg"
    },
    "content": "<p>Finished reading the first chapter today.</p>",
    "contentPlainText": "Finished reading the first chapter today.",
    "media": [
      {
        "_id": "66f1a2b3c4d5e6f708192a3c",
        "s3Key": "community/videos/0b9c1e0e-6a53-4c0b-9a0a-3f1f0f7f2a11-clip.mp4",
        "fileName": "clip.mp4",
        "fileType": "video/mp4",
        "fileSize": 10485760,
        "mediaType": "video",
        "thumbnailKey": "community/thumbnails/7d2f6c1a-2f0e-4a53-8a61-1c2b3d4e5f60.jpg"
      }
    ],
    "likes": [],
    "likesCount": 0,
    "commentsCount": 0,
    "isDeleted": false,
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-09-18T10:15:00.000Z",
    "updatedAt": "2026-09-18T10:15:00.000Z",
    "__v": 0
  }
}
GET/community/posts

Get the community feed

Auth required

Returns all non-deleted posts from all users, newest first (the feed is global — it is not limited to followed users). Page-based pagination via `page` and `limit` (no upper bound is enforced on `limit`). Each media item gets a 1-hour presigned `url` (and `thumbnailUrl` for videos). The raw `likes` array is removed and replaced by a `hasLiked` flag for the current user.

Query parameters

page
number
1-based page number.Default: 1
limit
number
Posts per page.Default: 10

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 500Database error
Request
curl -X GET "https://app.ummahspot.com/community/posts" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "posts": [
    {
      "_id": "66f1a2b3c4d5e6f708192a3b",
      "author": {
        "_id": "64d0f1e2a3b4c5d6e7f80910",
        "username": "abdullah",
        "profilePicture": "https://bucket.s3.amazonaws.com/profile-pictures/abc.jpg?X-Amz-Signature=...",
        "profilePictureKey": "profile-pictures/abc.jpg"
      },
      "content": "<p>Finished reading the first chapter today.</p>",
      "contentPlainText": "Finished reading the first chapter today.",
      "media": [
        {
          "_id": "66f1a2b3c4d5e6f708192a3c",
          "s3Key": "community/images/0b9c1e0e-6a53-4c0b-9a0a-3f1f0f7f2a11-page.png",
          "fileName": "page.png",
          "fileType": "image/png",
          "fileSize": 482113,
          "mediaType": "image",
          "url": "https://bucket.s3.amazonaws.com/community/images/0b9c1e0e-...-page.png?X-Amz-Signature=..."
        }
      ],
      "likesCount": 3,
      "commentsCount": 1,
      "isDeleted": false,
      "deletedAt": null,
      "deletedBy": null,
      "createdAt": "2026-09-18T10:15:00.000Z",
      "updatedAt": "2026-09-18T10:20:00.000Z",
      "__v": 3,
      "hasLiked": true
    }
  ],
  "currentPage": 1,
  "totalPages": 5,
  "totalPosts": 42
}
GET/community/posts/:postId

Get a single post

Auth required

Returns one non-deleted post with 1-hour presigned media URLs and a `hasLiked` flag for the current user (the raw `likes` array is removed).

Path parameters

postId
string
Post ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Post not found or deleted
  • 500Database error (including a malformed `postId`)
Request
curl -X GET "https://app.ummahspot.com/community/posts/:postId" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "post": {
    "_id": "66f1a2b3c4d5e6f708192a3b",
    "author": {
      "_id": "64d0f1e2a3b4c5d6e7f80910",
      "username": "abdullah",
      "profilePicture": "https://lh3.googleusercontent.com/a/photo.jpg"
    },
    "content": "<p>Finished reading the first chapter today.</p>",
    "contentPlainText": "Finished reading the first chapter today.",
    "media": [
      {
        "_id": "66f1a2b3c4d5e6f708192a3c",
        "s3Key": "community/videos/0b9c1e0e-...-clip.mp4",
        "fileName": "clip.mp4",
        "fileType": "video/mp4",
        "fileSize": 10485760,
        "mediaType": "video",
        "thumbnailKey": "community/thumbnails/7d2f6c1a-....jpg",
        "url": "https://bucket.s3.amazonaws.com/community/videos/...?X-Amz-Signature=...",
        "thumbnailUrl": "https://bucket.s3.amazonaws.com/community/thumbnails/...?X-Amz-Signature=..."
      }
    ],
    "likesCount": 3,
    "commentsCount": 1,
    "isDeleted": false,
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-09-18T10:15:00.000Z",
    "updatedAt": "2026-09-18T10:20:00.000Z",
    "__v": 3,
    "hasLiked": false
  }
}
PUT/community/posts/:postId

Edit a post

Auth required

Updates the text of a post. Only the post author may edit (admins cannot edit other users' posts). Media cannot be changed. An empty `content` is ignored rather than applied. Unlike the read endpoints, the response returns the stored document as-is: it includes the raw `likes` array of user IDs, has no `hasLiked` flag and no presigned media URLs.

Path parameters

postId
string
Post ObjectId

Body parameters

content
string
New post body. Ignored when empty.
contentPlainText
string
New plain-text version. Applied whenever the key is present (may be an empty string).

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 403The current user is not the post author
  • 404Post not found or deleted
  • 500Database error
Request
curl -X PUT "https://app.ummahspot.com/community/posts/:postId" \
  -H "Authorization: Bearer $SHARH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"string"}'
Response · 200
{
  "post": {
    "_id": "66f1a2b3c4d5e6f708192a3b",
    "author": {
      "_id": "64d0f1e2a3b4c5d6e7f80910",
      "username": "abdullah",
      "profilePicture": "https://lh3.googleusercontent.com/a/photo.jpg"
    },
    "content": "<p>Finished the first two chapters today.</p>",
    "contentPlainText": "Finished the first two chapters today.",
    "media": [],
    "likes": ["64d0f1e2a3b4c5d6e7f80999"],
    "likesCount": 1,
    "commentsCount": 0,
    "isDeleted": false,
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-09-18T10:15:00.000Z",
    "updatedAt": "2026-09-18T11:02:00.000Z",
    "__v": 1
  }
}
DELETE/community/posts/:postId

Delete a post

Auth required

Soft-deletes a post (sets `isDeleted`, `deletedAt`, `deletedBy`). Allowed for the post author or any admin. Deleted posts disappear from every read endpoint.

Path parameters

postId
string
Post ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 403The current user is neither the author nor an admin
  • 404Post not found or already deleted
  • 500Database error
Request
curl -X DELETE "https://app.ummahspot.com/community/posts/:postId" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "message": "Post deleted successfully"
}
POST/community/posts/:postId/like

Toggle like on a post

Auth required

Likes the post if the current user has not liked it yet, otherwise removes the like. When a like is added, the post author is sent a `like_on_post` notification. No request body.

Path parameters

postId
string
Post ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Post not found or deleted
  • 500Database error
Request
curl -X POST "https://app.ummahspot.com/community/posts/:postId/like" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "hasLiked": true,
  "likesCount": 4
}
POST/community/posts/:postId/comments

Comment on a post or reply to a comment

Auth required

Creates a top-level comment, or a reply when `parentComment` is given. Replies are limited to one level: the parent must be a non-deleted top-level comment on the same post. Recalculates the post's `commentsCount` (and the parent's `repliesCount`). Sends a `comment_on_post` notification to the post author, or a `reply_to_comment` notification to the parent comment's author. Comment content is limited to 2000 characters by the model (longer content fails with a 500).

Path parameters

postId
string
Post ObjectId

Body parameters

contentrequired
string
Comment text, max 2000 characters.
parentComment
string
ObjectId of the top-level comment being replied to. Omit for a top-level comment.Default: null

Errors

  • 400`content` is missing, or `parentComment` is itself a reply (replies can only be one level deep)
  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Post not found or deleted, or parent comment not found on this post
  • 500Database/validation error (e.g. content over 2000 characters)
Request
curl -X POST "https://app.ummahspot.com/community/posts/:postId/comments" \
  -H "Authorization: Bearer $SHARH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"string"}'
Response · 201
{
  "comment": {
    "_id": "66f1b0c1d2e3f4a5b6c7d8e9",
    "post": "66f1a2b3c4d5e6f708192a3b",
    "author": {
      "_id": "64d0f1e2a3b4c5d6e7f80910",
      "username": "abdullah",
      "profilePicture": "https://lh3.googleusercontent.com/a/photo.jpg"
    },
    "parentComment": null,
    "content": "JazakAllahu khayran, very helpful.",
    "likes": [],
    "likesCount": 0,
    "repliesCount": 0,
    "isDeleted": false,
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-09-18T10:30:00.000Z",
    "updatedAt": "2026-09-18T10:30:00.000Z",
    "__v": 0
  }
}
GET/community/posts/:postId/comments

List top-level comments on a post

Auth required

Returns the non-deleted top-level comments of a post, oldest first, with page-based pagination. Replies are not included — use `repliesCount` and the replies endpoint. The raw `likes` array is replaced by a `hasLiked` flag. The handler does not check that the post itself exists; an unknown post simply yields an empty list.

Path parameters

postId
string
Post ObjectId

Query parameters

page
number
1-based page number.Default: 1
limit
number
Comments per page.Default: 20

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 500Database error (including a malformed `postId`)
Request
curl -X GET "https://app.ummahspot.com/community/posts/:postId/comments" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "comments": [
    {
      "_id": "66f1b0c1d2e3f4a5b6c7d8e9",
      "post": "66f1a2b3c4d5e6f708192a3b",
      "author": {
        "_id": "64d0f1e2a3b4c5d6e7f80910",
        "username": "abdullah",
        "profilePicture": "https://lh3.googleusercontent.com/a/photo.jpg"
      },
      "parentComment": null,
      "content": "JazakAllahu khayran, very helpful.",
      "likesCount": 2,
      "repliesCount": 1,
      "isDeleted": false,
      "deletedAt": null,
      "deletedBy": null,
      "createdAt": "2026-09-18T10:30:00.000Z",
      "updatedAt": "2026-09-18T10:45:00.000Z",
      "__v": 2,
      "hasLiked": false
    }
  ],
  "currentPage": 1,
  "totalPages": 1,
  "totalComments": 1
}
POST/community/comments/:commentId/like

Toggle like on a comment

Auth required

Likes the comment (or reply) if the current user has not liked it yet, otherwise removes the like. When a like is added, the comment author is sent a `like_on_comment` notification. No request body.

Path parameters

commentId
string
Comment ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Comment not found or deleted
  • 500Database error
Request
curl -X POST "https://app.ummahspot.com/community/comments/:commentId/like" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "hasLiked": false,
  "likesCount": 1
}
GET/community/comments/:commentId/replies

List replies to a comment

Auth required

Returns the non-deleted replies to a comment, oldest first, with page-based pagination. The raw `likes` array is replaced by a `hasLiked` flag. The handler does not check that the parent comment exists; an unknown ID yields an empty list.

Path parameters

commentId
string
ObjectId of the parent (top-level) comment

Query parameters

page
number
1-based page number.Default: 1
limit
number
Replies per page.Default: 20

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 500Database error (including a malformed `commentId`)
Request
curl -X GET "https://app.ummahspot.com/community/comments/:commentId/replies" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "replies": [
    {
      "_id": "66f1b4d5e6f7a8b9c0d1e2f3",
      "post": "66f1a2b3c4d5e6f708192a3b",
      "author": {
        "_id": "64d0f1e2a3b4c5d6e7f80999",
        "username": "maryam",
        "profilePicture": "https://lh3.googleusercontent.com/a/other.jpg"
      },
      "parentComment": "66f1b0c1d2e3f4a5b6c7d8e9",
      "content": "Wa iyyak!",
      "likesCount": 0,
      "repliesCount": 0,
      "isDeleted": false,
      "deletedAt": null,
      "deletedBy": null,
      "createdAt": "2026-09-18T10:45:00.000Z",
      "updatedAt": "2026-09-18T10:45:00.000Z",
      "__v": 0,
      "hasLiked": false
    }
  ],
  "currentPage": 1,
  "totalPages": 1,
  "totalReplies": 1
}
PUT/community/comments/:commentId

Edit a comment

Auth required

Updates the text of a comment or reply. Only the comment author may edit (admins cannot edit other users' comments). An empty `content` is ignored. The response returns the stored document as-is, including the raw `likes` array of user IDs and no `hasLiked` flag.

Path parameters

commentId
string
Comment ObjectId

Body parameters

content
string
New comment text, max 2000 characters. Ignored when empty.

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 403The current user is not the comment author
  • 404Comment not found or deleted
  • 500Database/validation error (e.g. content over 2000 characters)
Request
curl -X PUT "https://app.ummahspot.com/community/comments/:commentId" \
  -H "Authorization: Bearer $SHARH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"string"}'
Response · 200
{
  "comment": {
    "_id": "66f1b0c1d2e3f4a5b6c7d8e9",
    "post": "66f1a2b3c4d5e6f708192a3b",
    "author": {
      "_id": "64d0f1e2a3b4c5d6e7f80910",
      "username": "abdullah",
      "profilePicture": "https://lh3.googleusercontent.com/a/photo.jpg"
    },
    "parentComment": null,
    "content": "JazakAllahu khayran, this was very helpful.",
    "likes": ["64d0f1e2a3b4c5d6e7f80999"],
    "likesCount": 1,
    "repliesCount": 1,
    "isDeleted": false,
    "deletedAt": null,
    "deletedBy": null,
    "createdAt": "2026-09-18T10:30:00.000Z",
    "updatedAt": "2026-09-18T11:10:00.000Z",
    "__v": 1
  }
}
DELETE/community/comments/:commentId

Delete a comment

Auth required

Soft-deletes a comment or reply. Allowed for the comment author or any admin. Recalculates the post's `commentsCount` and, for a reply, the parent's `repliesCount`. Replies to a deleted top-level comment are not themselves deleted.

Path parameters

commentId
string
Comment ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 403The current user is neither the author nor an admin
  • 404Comment not found or already deleted
  • 500Database error
Request
curl -X DELETE "https://app.ummahspot.com/community/comments/:commentId" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "message": "Comment deleted successfully"
}
POST/community/reports

Report a post or comment

Auth required

Submits a moderation report against a non-deleted post or comment. A user can report a given target only once (unique on reporter + targetType + targetId). New reports start with status `pending`. `reason` must be one of the model's enum values; any other value fails validation and is answered with a 500.

Body parameters

targetTyperequired
string
`'post'` or `'comment'`.
targetIdrequired
string
ObjectId of the post or comment being reported.
reasonrequired
string
One of `'spam'`, `'harassment'`, `'inappropriate_content'`, `'misinformation'`, `'other'`.
details
string
Free-text explanation.Default: ''

Errors

  • 400`targetType`, `targetId` or `reason` missing, or `targetType` is not `post`/`comment`
  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Target post or comment not found (or deleted)
  • 409The current user has already reported this content
  • 500Database/validation error (e.g. `reason` not in the allowed list)
Request
curl -X POST "https://app.ummahspot.com/community/reports" \
  -H "Authorization: Bearer $SHARH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"targetType":"string","targetId":"string","reason":"string"}'
Response · 201
{
  "report": {
    "_id": "66f1c7e8f9a0b1c2d3e4f5a6",
    "reporter": "64d0f1e2a3b4c5d6e7f80910",
    "targetType": "post",
    "targetId": "66f1a2b3c4d5e6f708192a3b",
    "reason": "spam",
    "details": "Repeated advertising links",
    "status": "pending",
    "reviewedBy": null,
    "actionTaken": null,
    "reviewedAt": null,
    "createdAt": "2026-09-18T11:20:00.000Z",
    "updatedAt": "2026-09-18T11:20:00.000Z",
    "__v": 0
  }
}
POST/community/users/:userId/follow

Toggle follow on a user

Auth required

Follows the target user if not already followed, otherwise unfollows. Updates `followersCount` on the target and `followingCount` on the current user. No request body.

Path parameters

userId
string
ObjectId of the user to follow or unfollow

Errors

  • 400`userId` is the current user (you cannot follow yourself)
  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404Target user not found
  • 500Database error
Request
curl -X POST "https://app.ummahspot.com/community/users/:userId/follow" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "isFollowing": true
}
GET/community/users/:userId/follow-counts

Get follower and following counts

Auth required

Lightweight lookup of a user's follower/following counters. Missing counters are returned as 0.

Path parameters

userId
string
User ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404User not found
  • 500Database error
Request
curl -X GET "https://app.ummahspot.com/community/users/:userId/follow-counts" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "followersCount": 12,
  "followingCount": 5
}
GET/community/users/:userId/profile

Get a user's community profile

Auth required

Returns the public community profile of a user plus whether the current user follows them. `profilePicture` is a 1-hour presigned URL when the user uploaded a picture, otherwise the stored (e.g. Google) picture URL.

Path parameters

userId
string
User ObjectId

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 404User not found
  • 500Database error
Request
curl -X GET "https://app.ummahspot.com/community/users/:userId/profile" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "user": {
    "_id": "64d0f1e2a3b4c5d6e7f80999",
    "username": "maryam",
    "profilePicture": "https://lh3.googleusercontent.com/a/other.jpg",
    "followersCount": 12,
    "followingCount": 5,
    "createdAt": "2025-03-02T08:00:00.000Z",
    "isFollowing": true
  }
}
GET/community/users/:userId/posts

List a user's posts

Auth required

Returns the non-deleted posts written by one user, newest first, with page-based pagination. Same item shape as the feed: 1-hour presigned media URLs and a `hasLiked` flag instead of the raw `likes` array. The handler does not check that the user exists; an unknown ID yields an empty list.

Path parameters

userId
string
ObjectId of the post author

Query parameters

page
number
1-based page number.Default: 1
limit
number
Posts per page.Default: 10

Errors

  • 401No bearer token provided (plain-text body)
  • 403Invalid or expired token, or the user lacks the required role (plain-text body)
  • 500Database error (including a malformed `userId`)
Request
curl -X GET "https://app.ummahspot.com/community/users/:userId/posts" \
  -H "Authorization: Bearer $SHARH_TOKEN"
Response · 200
{
  "posts": [
    {
      "_id": "66f1a2b3c4d5e6f708192a3b",
      "author": {
        "_id": "64d0f1e2a3b4c5d6e7f80999",
        "username": "maryam",
        "profilePicture": "https://lh3.googleusercontent.com/a/other.jpg"
      },
      "content": "<p>Notes from today's lesson.</p>",
      "contentPlainText": "Notes from today's lesson.",
      "media": [],
      "likesCount": 0,
      "commentsCount": 0,
      "isDeleted": false,
      "deletedAt": null,
      "deletedBy": null,
      "createdAt": "2026-09-17T18:00:00.000Z",
      "updatedAt": "2026-09-17T18:00:00.000Z",
      "__v": 0,
      "hasLiked": false
    }
  ],
  "currentPage": 1,
  "totalPages": 1,
  "totalPosts": 1
}