Skip to content

JendZ Posts & Comments System - Complete API Documentation

Overview

The JendZ Posts system provides a comprehensive content platform supporting 7 post types, secure location handling, hybrid feed architecture, and a fully separated comments system with unlimited nesting support.

Authentication

All authenticated endpoints require a Bearer token in the Authorization header:

Authorization: Bearer <your_access_token>

Enhanced Post Types

JendZ supports 7 different post types:

Post Type Description Location Handling
text Basic text post Auto-assigned to user's location
image Text with media files Auto-assigned to user's location
product_share Share a marketplace product Auto-assigned to user's location
store_share Share a marketplace store Auto-assigned to user's location
community_share Share a community Auto-assigned to user's location
poll Interactive poll with options Auto-assigned to user's location
audio Voice note/audio post Auto-assigned to user's location

Post Management API

Create Post

Endpoint: POST /api/feed/posts/

Authentication: Required

Content-Type: multipart/form-data (for media uploads) or application/json

Create Text Post (Neighbourhood)

Request:

POST /api/feed/posts/
Content-Type: application/json
Authorization: Bearer <token>

{
  "post_type": "text",
  "content": "Hello neighbourhood! Beautiful day today.",
  "title": "Good Morning" // optional
}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "user": {
    "username": "john_doe",
    "display_name": "John Doe",
    "profile_picture": "https://media.jendz.xyz/profiles/john.jpg"
  },
  "post_type": "text",
  "title": "Good Morning",
  "content": "Hello neighbourhood! Beautiful day today.",
  "media": [],
  "location": "550e8400-e29b-41d4-a716-446655440001",
  "location_name": "Downtown Lagos",
  "community": null,
  "community_name": null,
  "has_liked": false,
  "has_bookmarked": false,
  "likes_count": 0,
  "comments_count": 0,
  "views_count": 0,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}

Create Community Post

Request:

{
  "post_type": "text",
  "content": "Excited about our upcoming community event!",
  "community_id": "550e8400-e29b-41d4-a716-446655440002"
}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440003",
  "user": {
    "username": "community_member",
    "display_name": "Community Member",
    "profile_picture": "https://media.jendz.xyz/profiles/member.jpg"
  },
  "post_type": "text",
  "title": null,
  "content": "Excited about our upcoming community event!",
  "media": [],
  "location": null,
  "location_name": null,
  "community": "550e8400-e29b-41d4-a716-446655440002",
  "community_name": "Tech Enthusiasts Lagos",
  "has_liked": false,
  "has_bookmarked": false,
  "likes_count": 0,
  "comments_count": 0,
  "views_count": 0,
  "created_at": "2024-01-15T10:35:00Z",
  "updated_at": "2024-01-15T10:35:00Z"
}

Create Product Share

Request:

{
  "post_type": "product_share",
  "content": "Just found this amazing product! Perfect for our neighbourhood.",
  "shared_product_id": "550e8400-e29b-41d4-a716-446655440004"
}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440005",
  "user": {
    "username": "product_sharer",
    "display_name": "Product Sharer",
    "profile_picture": "https://media.jendz.xyz/profiles/sharer.jpg"
  },
  "post_type": "product_share",
  "content": "Just found this amazing product! Perfect for our neighbourhood.",
  "shared_product": {
    "id": "550e8400-e29b-41d4-a716-446655440004",
    "name": "Organic Honey 500ml",
    "price": "2500.00",
    "images": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440006",
        "url": "https://media.jendz.xyz/products/honey.jpg"
      }
    ],
    "store": {
      "id": "550e8400-e29b-41d4-a716-446655440007",
      "name": "Natural Foods Lagos"
    }
  },
  "location": "550e8400-e29b-41d4-a716-446655440001",
  "location_name": "Downtown Lagos",
  "community": null,
  "community_name": null,
  "likes_count": 0,
  "comments_count": 0,
  "views_count": 0,
  "created_at": "2024-01-15T11:00:00Z"
}

Create Poll

Request:

{
  "post_type": "poll",
  "content": "Community input needed for the new park development!",
  "poll_question": "What should be the main feature of our new community park?",
  "poll_options": [
    "Children's playground",
    "Sports field",
    "Garden area",
    "Community center"
  ],
  "poll_allows_multiple": false,
  "poll_expires_at": "2024-01-22T10:30:00Z"
}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440008",
  "user": {
    "username": "community_leader",
    "display_name": "Community Leader",
    "profile_picture": "https://media.jendz.xyz/profiles/leader.jpg"
  },
  "post_type": "poll",
  "content": "Community input needed for the new park development!",
  "poll_data": {
    "id": "550e8400-e29b-41d4-a716-446655440009",
    "question": "What should be the main feature of our new community park?",
    "allows_multiple_choices": false,
    "expires_at": "2024-01-22T10:30:00Z",
    "total_votes": 0,
    "user_voted": false,
    "is_expired": false,
    "options": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440010",
        "option_text": "Children's playground",
        "votes_count": 0,
        "order": 0,
        "user_voted": false,
        "percentage": 0
      },
      {
        "id": "550e8400-e29b-41d4-a716-446655440011",
        "option_text": "Sports field",
        "votes_count": 0,
        "order": 1,
        "user_voted": false,
        "percentage": 0
      }
    ]
  },
  "location": "550e8400-e29b-41d4-a716-446655440001",
  "location_name": "Downtown Lagos",
  "likes_count": 0,
  "comments_count": 0,
  "views_count": 0,
  "created_at": "2024-01-15T12:00:00Z"
}

Create Audio Post

Request:

POST /api/feed/posts/
Content-Type: multipart/form-data
Authorization: Bearer <token>

post_type=audio
content=My thoughts on today's community meeting
audio_file=<audio_file_binary_data>

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440012",
  "user": {
    "username": "audio_poster",
    "display_name": "Audio Poster",
    "profile_picture": "https://media.jendz.xyz/profiles/audio.jpg"
  },
  "post_type": "audio",
  "content": "My thoughts on today's community meeting",
  "audio_data": {
    "id": "550e8400-e29b-41d4-a716-446655440013",
    "audio_file": "https://media.jendz.xyz/posts/audio/meeting_thoughts.mp3",
    "duration_seconds": 125,
    "transcription": null,
    "waveform_data": null
  },
  "location": "550e8400-e29b-41d4-a716-446655440001",
  "location_name": "Downtown Lagos",
  "likes_count": 0,
  "comments_count": 0,
  "views_count": 0,
  "created_at": "2024-01-15T14:00:00Z"
}

Error Responses

Location Not Set (400 Bad Request):

{
  "error": "Location Required",
  "message": "Please set your location in profile settings before creating neighbourhood posts.",
  "action": "update_location"
}

Community Membership Required (400 Bad Request):

{
  "error": "Community Membership Required",
  "message": "You must join this community before you can post in it.",
  "action": "join_community",
  "community_id": "550e8400-e29b-41d4-a716-446655440002"
}

Validation Errors (400 Bad Request):

{
  "shared_product_id": ["This field is required for product share posts."],
  "poll_options": ["At least 2 poll options are required."]
}

Get Single Post

Endpoint: GET /api/feed/posts/{post_id}/

Authentication: Optional

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "user": {
    "username": "john_doe",
    "display_name": "John Doe",
    "profile_picture": "https://media.jendz.xyz/profiles/john.jpg"
  },
  "post_type": "text",
  "title": "Good Morning",
  "content": "Hello neighbourhood! Beautiful day today.",
  "media": [],
  "location": "550e8400-e29b-41d4-a716-446655440001",
  "location_name": "Downtown Lagos",
  "community": null,
  "community_name": null,
  "has_liked": false,
  "has_bookmarked": true,
  "likes_count": 15,
  "comments_count": 8,
  "views_count": 142,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}

Post Interactions

Like/Unlike Post

Endpoint: POST /api/feed/posts/{post_id}/like/

Authentication: Required

Request: Empty body

Response (Like Added):

{
  "message": "Post liked."
}

Response (Like Removed):

{
  "message": "Like removed."
}

Bookmark/Unbookmark Post

Endpoint: POST /api/feed/posts/{post_id}/bookmark/

Authentication: Required

Response (Bookmark Added):

{
  "message": "Post bookmarked."
}

Response (Bookmark Removed):

{
  "message": "Bookmark removed."
}

Track Post View

Endpoint: POST /api/feed/posts/{post_id}/track_view/

Authentication: Optional

Request (Optional):

{
  "device_type": "mobile",
  "referrer_type": "feed",
  "view_duration": 15
}

Response (View Recorded):

{
  "message": "View recorded"
}

Response (Cooldown Active):

{
  "message": "View not recorded - cooldown active"
}

Vote on Poll

Endpoint: POST /api/feed/posts/{post_id}/vote_poll/

Authentication: Required

Request (Single Choice):

{
  "option_ids": ["550e8400-e29b-41d4-a716-446655440010"]
}

Request (Multiple Choice):

{
  "option_ids": [
    "550e8400-e29b-41d4-a716-446655440010",
    "550e8400-e29b-41d4-a716-446655440011"
  ]
}

Response:

{
  "message": "Vote recorded successfully",
  "voted_options": ["Children's playground"]
}

Error Responses:

{
  "error": "This is not a poll post"
}
{
  "error": "This poll has expired"
}
{
  "error": "Multiple choices not allowed for this poll"
}

Hybrid Feed API

Neighbourhood Feed

Endpoint: GET /api/feed/hybrid/neighbourhood/

Authentication: Required

Query Parameters:

  • page (integer): Page number (default: 1)
  • page_size (integer): Items per page (default: 15, max: 50)

Response:

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "user": {
        "username": "local_user",
        "display_name": "Local User",
        "profile_picture": "https://media.jendz.xyz/profiles/local.jpg"
      },
      "post_type": "text",
      "content": "New coffee shop just opened on Main Street!",
      "location": "550e8400-e29b-41d4-a716-446655440001",
      "location_name": "Downtown Lagos",
      "community": null,
      "likes_count": 5,
      "comments_count": 2,
      "views_count": 28,
      "created_at": "2024-01-15T09:00:00Z"
    }
  ],
  "has_more": true,
  "feed_type": "neighbourhood",
  "location_info": {
    "name": "Downtown Lagos",
    "location_id": "550e8400-e29b-41d4-a716-446655440001"
  },
  "enhancement_endpoints": [
    "/api/feed/enhancements/users/?location_id=550e8400-e29b-41d4-a716-446655440001",
    "/api/feed/enhancements/stores/?location_id=550e8400-e29b-41d4-a716-446655440001",
    "/api/feed/enhancements/communities/?location_id=550e8400-e29b-41d4-a716-446655440001"
  ]
}

General Feed

Endpoint: GET /api/feed/hybrid/general/

Authentication: Required

Response:

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440020",
      "user": {
        "username": "global_user",
        "display_name": "Global User",
        "profile_picture": "https://media.jendz.xyz/profiles/global.jpg"
      },
      "post_type": "product_share",
      "content": "Amazing local artisan crafts!",
      "shared_product": {
        "id": "550e8400-e29b-41d4-a716-446655440021",
        "name": "Handwoven Basket",
        "price": "3500.00"
      },
      "location": "550e8400-e29b-41d4-a716-446655440022",
      "location_name": "Victoria Island",
      "likes_count": 12,
      "comments_count": 4,
      "views_count": 89,
      "created_at": "2024-01-15T08:30:00Z"
    }
  ],
  "has_more": true,
  "feed_type": "general",
  "enhancement_endpoints": [
    "/api/feed/enhancements/users/",
    "/api/feed/enhancements/stores/",
    "/api/feed/enhancements/communities/"
  ]
}

Location-Specific Feed

Endpoint: GET /api/feed/hybrid/location/{location_id}/

Authentication: Required

Response:

{
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440030",
      "user": {
        "username": "visitor",
        "display_name": "Visitor User",
        "profile_picture": "https://media.jendz.xyz/profiles/visitor.jpg"
      },
      "post_type": "poll",
      "content": "What's the best restaurant in this area?",
      "poll_data": {
        "question": "What's the best restaurant in this area?",
        "total_votes": 25,
        "user_voted": false,
        "options": [
          {
            "option_text": "Lagos Kitchen",
            "votes_count": 15,
            "percentage": 60.0
          }
        ]
      },
      "location": "550e8400-e29b-41d4-a716-446655440031",
      "location_name": "Ikeja",
      "created_at": "2024-01-15T07:15:00Z"
    }
  ],
  "has_more": false,
  "feed_type": "location_specific",
  "can_post": false,
  "location_info": {
    "name": "Ikeja",
    "location_id": "550e8400-e29b-41d4-a716-446655440031"
  },
  "enhancement_endpoints": [
    "/api/feed/enhancements/users/?location_id=550e8400-e29b-41d4-a716-446655440031",
    "/api/feed/enhancements/stores/?location_id=550e8400-e29b-41d4-a716-446655440031",
    "/api/feed/enhancements/communities/?location_id=550e8400-e29b-41d4-a716-446655440031"
  ]
}

Feed Enhancement Endpoints

Nearby Users

Endpoint: GET /api/feed/enhancements/users/

Authentication: Required

Query Parameters:

  • location_id (UUID, optional): Filter by specific location

Response:

{
  "type": "users",
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440040",
      "username": "nearby_user1",
      "display_name": "Nearby User One",
      "profile_picture": "https://media.jendz.xyz/profiles/nearby1.jpg",
      "bio": "Local photographer and coffee enthusiast"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440041",
      "username": "nearby_user2",
      "display_name": "Nearby User Two",
      "profile_picture": "https://media.jendz.xyz/profiles/nearby2.jpg",
      "bio": "Community organizer"
    }
  ],
  "inject_at_positions": [5, 15, 25],
  "title": "People nearby"
}

Endpoint: GET /api/feed/enhancements/stores/

Authentication: Required

Query Parameters:

  • location_id (UUID, optional): Filter by specific location

Response:

{
  "type": "stores",
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440050",
      "name": "Fresh Market Lagos",
      "description": "Organic fruits and vegetables from local farms",
      "logo": "https://media.jendz.xyz/stores/fresh_market_logo.jpg",
      "location_name": "Downtown Lagos",
      "owner": {
        "username": "market_owner",
        "display_name": "Market Owner"
      }
    }
  ],
  "inject_at_positions": [8, 20],
  "title": "Trending stores"
}

Suggested Communities

Endpoint: GET /api/feed/enhancements/communities/

Authentication: Required

Query Parameters:

  • location_id (UUID, optional): Filter by specific location

Response:

{
  "type": "communities",
  "items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440060",
      "name": "Lagos Fitness Group",
      "description": "Weekly workouts and healthy living discussions",
      "avatar": "https://media.jendz.xyz/communities/fitness_avatar.jpg",
      "members_count": 156,
      "posts_count": 42,
      "category": {
        "id": "550e8400-e29b-41d4-a716-446655440061",
        "name": "Health & Fitness"
      }
    }
  ],
  "inject_at_positions": [12, 24],
  "title": "Suggested communities"
}

Comments API

Get Comments for Post

Endpoint: GET /api/posts/posts/{post_id}/comments/

Authentication: Optional

Query Parameters:

  • page (integer): Page number (default: 1)
  • page_size (integer): Items per page (default: 20, max: 100)

Response:

{
  "count": 45,
  "next": "http://api.example.com/api/posts/posts/550e8400-e29b-41d4-a716-446655440000/comments/?page=2",
  "previous": null,
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440070",
      "user": {
        "username": "commenter1",
        "display_name": "First Commenter",
        "profile_picture": "https://media.jendz.xyz/profiles/commenter1.jpg"
      },
      "post": "550e8400-e29b-41d4-a716-446655440000",
      "content": "Great neighbourhood post! Thanks for sharing.",
      "parent": null,
      "replies_count": 3,
      "likes_count": 5,
      "bookmarks_count": 1,
      "views_count": 25,
      "has_liked": false,
      "has_bookmarked": false,
      "created_at": "2024-01-15T11:00:00Z",
      "updated_at": "2024-01-15T11:00:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440071",
      "user": {
        "username": "commenter2",
        "display_name": "Second Commenter",
        "profile_picture": "https://media.jendz.xyz/profiles/commenter2.jpg"
      },
      "post": "550e8400-e29b-41d4-a716-446655440000",
      "content": "I totally agree! The community spirit is amazing here.",
      "parent": null,
      "replies_count": 0,
      "likes_count": 2,
      "bookmarks_count": 0,
      "views_count": 18,
      "has_liked": true,
      "has_bookmarked": false,
      "created_at": "2024-01-15T11:15:00Z",
      "updated_at": "2024-01-15T11:15:00Z"
    }
  ]
}

Get Replies to Comment

Endpoint: GET /api/posts/comments/replies/

Authentication: Optional

Query Parameters:

  • parent_id (UUID, required): ID of parent comment
  • page (integer): Page number (default: 1)
  • page_size (integer): Items per page (default: 20, max: 100)

Response:

{
  "count": 8,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440080",
      "user": {
        "username": "replier1",
        "display_name": "Reply User One",
        "profile_picture": "https://media.jendz.xyz/profiles/replier1.jpg"
      },
      "post": "550e8400-e29b-41d4-a716-446655440000",
      "content": "I completely agree with your comment!",
      "parent": "550e8400-e29b-41d4-a716-446655440070",
      "replies_count": 1,
      "likes_count": 2,
      "bookmarks_count": 0,
      "views_count": 12,
      "has_liked": true,
      "has_bookmarked": false,
      "created_at": "2024-01-15T11:30:00Z",
      "updated_at": "2024-01-15T11:30:00Z"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440081",
      "user": {
        "username": "replier2",
        "display_name": "Reply User Two",
        "profile_picture": "https://media.jendz.xyz/profiles/replier2.jpg"
      },
      "post": "550e8400-e29b-41d4-a716-446655440000",
      "content": "Thanks for the positive feedback!",
      "parent": "550e8400-e29b-41d4-a716-446655440070",
      "replies_count": 0,
      "likes_count": 1,
      "bookmarks_count": 0,
      "views_count": 8,
      "has_liked": false,
      "has_bookmarked": false,
      "created_at": "2024-01-15T11:45:00Z",
      "updated_at": "2024-01-15T11:45:00Z"
    }
  ]
}

Create Comment or Reply

Endpoint: POST /api/posts/comments/

Authentication: Required

Create Top-Level Comment

Request:

{
  "post": "550e8400-e29b-41d4-a716-446655440000",
  "content": "This is a great neighbourhood post!",
  "parent": null
}

Create Reply to Comment

Request:

{
  "post": "550e8400-e29b-41d4-a716-446655440000",
  "content": "I totally agree with your comment!",
  "parent": "550e8400-e29b-41d4-a716-446655440070"
}

Response:

{
  "id": "550e8400-e29b-41d4-a716-446655440090",
  "user": {
    "username": "current_user",
    "display_name": "Current User",
    "profile_picture": "https://media.jendz.xyz/profiles/current.jpg"
  },
  "post": "550e8400-e29b-41d4-a716-446655440000",
  "content": "This is a great neighbourhood post!",
  "parent": null,
  "replies_count": 0,
  "likes_count": 0,
  "bookmarks_count": 0,
  "views_count": 0,
  "has_liked": false,
  "has_bookmarked": false,
  "created_at": "2024-01-15T12:00:00Z",
  "updated_at": "2024-01-15T12:00:00Z"
}

Validation Error (400 Bad Request):

{
  "content": ["This field is required."],
  "post": ["This field is required."]
}

Like/Unlike Comment

Endpoint: POST /api/posts/comments/{comment_id}/like/

Authentication: Required

Request: Empty body

Response (Like Added):

{
  "message": "Comment liked."
}

Response (Like Removed):

{
  "message": "Like removed."
}

Bookmark/Unbookmark Comment

Endpoint: POST /api/posts/comments/{comment_id}/bookmark/

Authentication: Required

Response (Bookmark Added):

{
  "message": "Comment bookmarked."
}

Response (Bookmark Removed):

{
  "message": "Bookmark removed."
}

User Collections

Get Liked Posts

Endpoint: GET /api/feed/posts/liked/

Authentication: Required

Response:

{
  "count": 23,
  "next": "http://api.example.com/api/feed/posts/liked/?page=2",
  "previous": null,
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440100",
      "user": {
        "username": "liked_author",
        "display_name": "Liked Author",
        "profile_picture": "https://media.jendz.xyz/profiles/liked.jpg"
      },
      "post_type": "text",
      "content": "Amazing sunset today!",
      "location_name": "Victoria Island",
      "has_liked": true,
      "likes_count": 45,
      "comments_count": 12,
      "created_at": "2024-01-14T18:30:00Z"
    }
  ]
}

Get Bookmarked Posts

Endpoint: GET /api/feed/posts/bookmarked/

Authentication: Required

Response:

{
  "count": 15,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440110",
      "user": {
        "username": "bookmarked_author",
        "display_name": "Bookmarked Author",
        "profile_picture": "https://media.jendz.xyz/profiles/bookmarked.jpg"
      },
      "post_type": "product_share",
      "content": "Perfect for home organization!",
      "shared_product": {
        "id": "550e8400-e29b-41d4-a716-446655440111",
        "name": "Storage Containers Set",
        "price": "4500.00"
      },
      "has_bookmarked": true,
      "likes_count": 28,
      "comments_count": 6,
      "created_at": "2024-01-13T15:20:00Z"
    }
  ]
}

Analytics & Discovery

Endpoint: GET /api/feed/posts/popular_locations/

Authentication: Optional

Response:

{
  "count": 20,
  "locations": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440120",
      "name": "Downtown Lagos",
      "post_count": 245,
      "country": "Nigeria",
      "state": "Lagos State",
      "city": "Lagos",
      "neighbourhood": "Downtown Lagos"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440121",
      "name": "Victoria Island",
      "post_count": 189,
      "country": "Nigeria",
      "state": "Lagos State",
      "city": "Lagos",
      "neighbourhood": "Victoria Island"
    },
    {
      "id": "550e8400-e29b-41d4-a716-446655440122",
      "name": "Ikeja",
      "post_count": 156,
      "country": "Nigeria",
      "state": "Lagos State",
      "city": "Lagos",
      "neighbourhood": "Ikeja"
    }
  ]
}

User Analytics

Endpoint: GET /api/feed/posts/user_analytics/

Authentication: Required

Response:

{
  "total_views": 1250,
  "unique_posts_viewed": 892,
  "repeat_view_ratio": 0.286,
  "popular_locations": [
    {
      "post__location__name": "Downtown Lagos",
      "view_count": 145
    },
    {
      "post__location__name": "Victoria Island",
      "view_count": 89
    },
    {
      "post__location__name": "Ikeja",
      "view_count": 67
    }
  ],
  "avg_views_per_day": 12.5
}

Error Handling

HTTP Status Codes

  • 200 OK - Successful request
  • 201 Created - Resource created successfully
  • 400 Bad Request - Validation errors or malformed request
  • 401 Unauthorized - Authentication required or invalid token
  • 403 Forbidden - Permission denied
  • 404 Not Found - Resource not found
  • 429 Too Many Requests - Rate limit exceeded
  • 500 Internal Server Error - Server error

Common Error Response Format

{
  "detail": "Error message describing what went wrong",
  "field_errors": {
    "field_name": ["Specific validation error for this field"]
  }
}

Authentication Errors

401 Unauthorized:

{
  "detail": "Authentication credentials were not provided."
}

403 Forbidden:

{
  "detail": "You do not have permission to perform this action."
}

Validation Errors

400 Bad Request:

{
  "content": ["This field is required."],
  "poll_options": ["At least 2 poll options are required."],
  "shared_product_id": ["Invalid UUID format."]
}

Rate Limiting

429 Too Many Requests:

{
  "detail": "Too many requests. Please wait before trying again.",
  "retry_after": 60
}

Implementation Examples

cURL Examples

Create Text Post

curl -X POST "https://api.jendz.xyz/api/feed/posts/" \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "post_type": "text",
    "content": "Hello neighbourhood!",
    "title": "Good morning"
  }'

Create Poll

curl -X POST "https://api.jendz.xyz/api/feed/posts/" \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "post_type": "poll",
    "poll_question": "What should we do about the park?",
    "poll_options": ["Add playground", "More trees", "Sports area"],
    "poll_allows_multiple": false,
    "content": "Community input needed!"
  }'

Get Neighbourhood Feed

curl -X GET "https://api.jendz.xyz/api/feed/hybrid/neighbourhood/" \
  -H "Authorization: Bearer your_access_token"

Track Post View

curl -X POST "https://api.jendz.xyz/api/feed/posts/550e8400-e29b-41d4-a716-446655440000/track_view/" \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "device_type": "mobile",
    "referrer_type": "feed"
  }'

Create Comment

curl -X POST "https://api.jendz.xyz/api/posts/comments/" \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "post": "550e8400-e29b-41d4-a716-446655440000",
    "content": "Great post!",
    "parent": null
  }'

JavaScript/React Examples

Fetch Neighbourhood Feed

const fetchNeighbourhoodFeed = async () => {
  try {
    const response = await fetch("/api/feed/hybrid/neighbourhood/", {
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
    });

    const data = await response.json();

    if (response.ok) {
      setFeedItems(data.items);
      // Load enhancements in parallel
      loadEnhancements(data.enhancement_endpoints);
    } else {
      console.error("Feed loading failed:", data);
    }
  } catch (error) {
    console.error("Network error:", error);
  }
};

Create Post with Error Handling

const createPost = async (postData) => {
  try {
    const response = await fetch("/api/feed/posts/", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(postData),
    });

    const data = await response.json();

    if (response.ok) {
      console.log("Post created:", data);
      return data;
    } else if (response.status === 400) {
      if (data.action === "update_location") {
        showLocationDialog();
      } else if (data.action === "join_community") {
        showCommunityDialog(data.community_id);
      } else {
        showValidationErrors(data);
      }
    }
  } catch (error) {
    console.error("Error creating post:", error);
  }
};

Vote on Poll

const voteOnPoll = async (postId, optionIds) => {
  try {
    const response = await fetch(`/api/feed/posts/${postId}/vote_poll/`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${accessToken}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ option_ids: optionIds }),
    });

    const data = await response.json();

    if (response.ok) {
      console.log("Vote recorded:", data.voted_options);
      refreshPost(postId); // Refresh post to show updated results
    } else {
      console.error("Voting failed:", data.error);
    }
  } catch (error) {
    console.error("Error voting:", error);
  }
};

Python Requests Examples

Create Audio Post

import requests

def create_audio_post(access_token, content, audio_file_path):
    url = "https://api.jendz.xyz/api/feed/posts/"

    headers = {
        "Authorization": f"Bearer {access_token}"
    }

    data = {
        "post_type": "audio",
        "content": content
    }

    files = {
        "audio_file": open(audio_file_path, "rb")
    }

    try:
        response = requests.post(url, headers=headers, data=data, files=files)

        if response.status_code == 201:
            return response.json()
        else:
            print(f"Error: {response.status_code} - {response.json()}")
            return None

    except Exception as e:
        print(f"Request failed: {e}")
        return None
    finally:
        files["audio_file"].close()

Get Comments with Pagination

def get_all_comments(post_id, access_token=None):
    url = f"https://api.jendz.xyz/api/posts/posts/{post_id}/comments/"

    headers = {}
    if access_token:
        headers["Authorization"] = f"Bearer {access_token}"

    all_comments = []

    while url:
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            data = response.json()
            all_comments.extend(data["results"])
            url = data["next"]  # Next page URL or None
        else:
            print(f"Error fetching comments: {response.status_code}")
            break

    return all_comments

Data Models Summary

Post Model Fields

Field Type Description
id UUID Unique identifier
user Object Post author information
post_type String Type of post (text, image, product_share, etc.)
title String Optional post title
content String Post text content
media Array Attached media files
location UUID Auto-assigned location (neighbourhood posts)
location_name String Location display name
community UUID Community ID (community posts)
community_name String Community display name
shared_product Object Shared product details (product_share posts)
shared_store Object Shared store details (store_share posts)
shared_community Object Shared community details (community_share posts)
poll_data Object Poll details and options (poll posts)
audio_data Object Audio file and metadata (audio posts)
likes_count Integer Number of likes
comments_count Integer Number of comments
views_count Integer Number of views
has_liked Boolean Current user liked status
has_bookmarked Boolean Current user bookmark status
created_at DateTime Creation timestamp
updated_at DateTime Last modification timestamp

Comment Model Fields

Field Type Description
id UUID Unique identifier
user Object Comment author information
post UUID Associated post ID
content String Comment text
parent UUID Parent comment ID (null for top-level)
replies_count Integer Number of replies
likes_count Integer Number of likes
bookmarks_count Integer Number of bookmarks
views_count Integer Number of views
has_liked Boolean Current user liked status
has_bookmarked Boolean Current user bookmark status
created_at DateTime Creation timestamp
updated_at DateTime Last modification timestamp

Key Features & Characteristics

7 Enhanced Post Types - Text, image, product share, store share, community share, polls, audio
Secure Location Handling - Backend automatically assigns location, no frontend location data required
Hybrid Feed Architecture - Fast primary feed load (~200ms) with parallel enhancements
Separated Comments System - Independent loading with unlimited nesting depth
Real-time Interactions - Like, bookmark, vote with immediate feedback
Performance Optimized - Aggressive caching, lazy loading, efficient pagination
Comprehensive Error Handling - Clear error messages with actionable guidance
Analytics Integration - Essential view tracking for feed algorithms
Mobile-First Design - Optimized for mobile app performance and UX
RESTful API Design - Standard HTTP methods with predictable URL structure

This API provides a complete social platform foundation with advanced features for community engagement, content sharing, and real-time interaction while maintaining excellent performance and user experience.