# Sojorn API Reference

## 🚀 Complete REST API Documentation

**Version**: 3.0  
**Status**: ✅ **PRODUCTION READY**  
**Last Updated**: February 17, 2026

---

## 📋 Overview

The Sojorn API provides comprehensive REST endpoints for all platform features including authentication, posts, groups, beacons, E2EE chat, and more. All endpoints follow RESTful conventions and return JSON responses.

## 🔐 Authentication

### Base URL
```
Production: https://api.sojorn.app
Development: http://localhost:8080
```

### Authentication Methods
- **JWT Bearer Token**: `Authorization: Bearer <token>`
- **API Key**: `X-API-Key: <api-key>` (for service-to-service)
- **Session Cookie**: Automatic cookie-based authentication for web

### Token Endpoints

#### POST /auth/register
Register a new user account.

**Request:**
```json
{
  "email": "user@example.com",
  "password": "securePassword123",
  "handle": "username",
  "display_name": "Display Name"
}
```

**Response:**
```json
{
  "success": true,
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "handle": "username",
    "display_name": "Display Name",
    "created_at": "2026-02-17T12:00:00Z"
  },
  "token": "jwt_token_here",
  "refresh_token": "refresh_token_here"
}
```

#### POST /auth/login
Authenticate user and return tokens.

**Request:**
```json
{
  "email": "user@example.com",
  "password": "securePassword123"
}
```

**Response:**
```json
{
  "success": true,
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "handle": "username",
    "display_name": "Display Name"
  },
  "token": "jwt_token_here",
  "refresh_token": "refresh_token_here"
}
```

#### POST /auth/refresh
Refresh JWT access token.

**Request:**
```json
{
  "refresh_token": "refresh_token_here"
}
```

**Response:**
```json
{
  "success": true,
  "token": "new_jwt_token_here",
  "expires_at": "2026-02-18T12:00:00Z"
}
```

---

## 👤 User Management

### GET /users/me
Get current user profile.

**Headers:**
```
Authorization: Bearer <token>
```

**Response:**
```json
{
  "success": true,
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "handle": "username",
    "display_name": "Display Name",
    "bio": "User bio",
    "avatar_url": "https://cdn.sojorn.app/avatars/uuid.jpg",
    "follower_count": 150,
    "following_count": 75,
    "post_count": 42,
    "created_at": "2026-02-17T12:00:00Z",
    "is_verified": true,
    "is_premium": false
  }
}
```

### PUT /users/me
Update current user profile.

**Request:**
```json
{
  "display_name": "New Display Name",
  "bio": "Updated bio",
  "avatar_url": "https://cdn.sojorn.app/avatars/new.jpg",
  "location": "San Francisco, CA",
  "website": "https://example.com"
}
```

**Response:**
```json
{
  "success": true,
  "user": {
    "id": "uuid",
    "display_name": "New Display Name",
    "bio": "Updated bio",
    "avatar_url": "https://cdn.sojorn.app/avatars/new.jpg",
    "location": "San Francisco, CA",
    "website": "https://example.com"
  }
}
```

### GET /users/{handle}
Get user profile by handle.

**Response:**
```json
{
  "success": true,
  "user": {
    "id": "uuid",
    "handle": "username",
    "display_name": "Display Name",
    "bio": "User bio",
    "avatar_url": "https://cdn.sojorn.app/avatars/uuid.jpg",
    "follower_count": 150,
    "following_count": 75,
    "post_count": 42,
    "is_following": false,
    "is_blocked": false,
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

---

## 📝 Posts & Content

### GET /posts
Get posts with filtering and pagination.

**Query Parameters:**
- `limit`: Number of posts to return (default: 20, max: 100)
- `offset`: Pagination offset (default: 0)
- `category`: Filter by category
- `author_id`: Filter by author
- `has_video`: Filter by video content (true/false)
- `algorithm`: Use algorithmic ranking (true/false)

**Response:**
```json
{
  "success": true,
  "posts": [
    {
      "id": "uuid",
      "author_id": "uuid",
      "author_handle": "username",
      "author_avatar": "https://cdn.sojorn.app/avatars/uuid.jpg",
      "body": "Post content here",
      "image_url": "https://cdn.sojorn.app/posts/uuid.jpg",
      "video_url": "https://cdn.sojorn.app/videos/uuid.mp4",
      "thumbnail_url": "https://cdn.sojorn.app/thumbnails/uuid.jpg",
      "category": "general",
      "visibility": "public",
      "like_count": 25,
      "comment_count": 8,
      "repost_count": 3,
      "share_count": 2,
      "is_liked": false,
      "is_reposted": false,
      "is_saved": false,
      "created_at": "2026-02-17T12:00:00Z",
      "updated_at": "2026-02-17T12:00:00Z"
    }
  ],
  "pagination": {
    "total": 1000,
    "limit": 20,
    "offset": 0,
    "has_more": true
  }
}
```

### POST /posts
Create a new post.

**Request:**
```json
{
  "body": "Post content here",
  "category": "general",
  "visibility": "public",
  "image_url": "https://cdn.sojorn.app/posts/uuid.jpg",
  "video_url": "https://cdn.sojorn.app/videos/uuid.mp4",
  "thumbnail_url": "https://cdn.sojorn.app/thumbnails/uuid.jpg",
  "is_nsfw": false,
  "tags": ["tag1", "tag2"]
}
```

**Response:**
```json
{
  "success": true,
  "post": {
    "id": "uuid",
    "body": "Post content here",
    "category": "general",
    "visibility": "public",
    "image_url": "https://cdn.sojorn.app/posts/uuid.jpg",
    "video_url": "https://cdn.sojorn.app/videos/uuid.mp4",
    "thumbnail_url": "https://cdn.sojorn.app/thumbnails/uuid.jpg",
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### PUT /posts/{id}
Update an existing post.

**Request:**
```json
{
  "body": "Updated post content",
  "category": "general",
  "visibility": "public",
  "is_nsfw": false
}
```

**Response:**
```json
{
  "success": true,
  "post": {
    "id": "uuid",
    "body": "Updated post content",
    "updated_at": "2026-02-17T12:30:00Z"
  }
}
```

### DELETE /posts/{id}
Delete a post.

**Response:**
```json
{
  "success": true,
  "message": "Post deleted successfully"
}
```

---

## 💬 Comments

### GET /posts/{post_id}/comments
Get comments for a post.

**Query Parameters:**
- `limit`: Number of comments (default: 50)
- `offset`: Pagination offset

**Response:**
```json
{
  "success": true,
  "comments": [
    {
      "id": "uuid",
      "post_id": "uuid",
      "author_id": "uuid",
      "author_handle": "username",
      "author_avatar": "https://cdn.sojorn.app/avatars/uuid.jpg",
      "body": "Comment content",
      "like_count": 5,
      "reply_count": 2,
      "is_liked": false,
      "created_at": "2026-02-17T12:00:00Z"
    }
  ],
  "pagination": {
    "total": 100,
    "limit": 50,
    "offset": 0,
    "has_more": true
  }
}
```

### POST /posts/{post_id}/comments
Create a comment on a post.

**Request:**
```json
{
  "body": "Comment content",
  "parent_id": null
}
```

**Response:**
```json
{
  "success": true,
  "comment": {
    "id": "uuid",
    "body": "Comment content",
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

---

## 🔄 Reposts & Amplification

### POST /posts/{id}/repost
Create a repost.

**Request:**
```json
{
  "type": "standard",
  "comment": "Optional comment for quote repost"
}
```

**Response:**
```json
{
  "success": true,
  "repost": {
    "id": "uuid",
    "original_post_id": "uuid",
    "author_id": "uuid",
    "type": "standard",
    "comment": null,
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### POST /posts/{id}/boost
Boost a post for amplification.

**Request:**
```json
{
  "boost_type": "amplify",
  "boost_amount": 1
}
```

**Response:**
```json
{
  "success": true,
  "message": "Post boosted successfully"
}
```

### GET /posts/{id}/amplification
Get amplification analytics for a post.

**Response:**
```json
{
  "success": true,
  "analytics": {
    "post_id": "uuid",
    "total_amplification": 150,
    "amplification_rate": 0.75,
    "repost_counts": {
      "standard": 10,
      "quote": 5,
      "boost": 3,
      "amplify": 2
    },
    "metrics": [
      {
        "total_reach": 1000,
        "engagement_count": 75,
        "engagement_rate": 0.075,
        "new_followers": 5,
        "shares": 20,
        "comments": 15,
        "likes": 40,
        "last_updated": "2026-02-17T12:00:00Z"
      }
    ]
  }
}
```

---

## 📍 Beacons (Local Safety)

### GET /beacons
Get beacons with geospatial filtering.

**Query Parameters:**
- `lat`: Latitude for center point
- `lng`: Longitude for center point
- `radius_km`: Search radius in kilometers (default: 10)
- `category`: Filter by category
- `status`: Filter by status
- `only_official`: Filter for official sources only

**Response:**
```json
{
  "success": true,
  "beacons": [
    {
      "id": "uuid",
      "title": "Community Event",
      "description": "Description of the beacon",
      "category": "event",
      "status": "active",
      "lat": 37.7749,
      "lng": -122.4194,
      "author_id": "uuid",
      "author_handle": "username",
      "is_verified": true,
      "is_official_source": true,
      "organization_name": "City Hall",
      "vouch_count": 25,
      "report_count": 0,
      "confidence_score": 0.95,
      "image_url": "https://cdn.sojorn.app/beacons/uuid.jpg",
      "action_items": [
        "Volunteer at the event",
        "Share with neighbors"
      ],
      "neighborhood": "Downtown",
      "created_at": "2026-02-17T12:00:00Z"
    }
  ]
}
```

### POST /beacons
Create a new beacon.

**Request:**
```json
{
  "title": "Community Event",
  "description": "Description of the beacon",
  "category": "event",
  "lat": 37.7749,
  "lng": -122.4194,
  "image_url": "https://cdn.sojorn.app/beacons/uuid.jpg",
  "action_items": [
    "Volunteer at the event",
    "Share with neighbors"
  ],
  "neighborhood": "Downtown"
}
```

**Response:**
```json
{
  "success": true,
  "beacon": {
    "id": "uuid",
    "title": "Community Event",
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### POST /beacons/{id}/vouch
Vouch for a beacon (positive interaction).

**Response:**
```json
{
  "success": true,
  "vouch_count": 26,
  "confidence_score": 0.96
}
```

### POST /beacons/{id}/report
Report a beacon (negative interaction).

**Request:**
```json
{
  "reason": "inaccurate_information",
  "comment": "This information is not accurate"
}
```

**Response:**
```json
{
  "success": true,
  "report_count": 1,
  "confidence_score": 0.90
}
```

---

## 👥 Groups

### GET /groups
Get groups with filtering.

**Query Parameters:**
- `limit`: Number of groups (default: 20)
- `offset`: Pagination offset
- `category`: Filter by category
- `is_private`: Filter by privacy setting

**Response:**
```json
{
  "success": true,
  "groups": [
    {
      "id": "uuid",
      "name": "Group Name",
      "description": "Group description",
      "category": "general",
      "is_private": false,
      "member_count": 150,
      "post_count": 500,
      "avatar_url": "https://cdn.sojorn.app/groups/uuid.jpg",
      "banner_url": "https://cdn.sojorn.app/groups/banner/uuid.jpg",
      "created_by": "uuid",
      "created_at": "2026-02-17T12:00:00Z",
      "is_member": false,
      "is_admin": false
    }
  ],
  "pagination": {
    "total": 100,
    "limit": 20,
    "offset": 0,
    "has_more": true
  }
}
```

### POST /groups
Create a new group.

**Request:**
```json
{
  "name": "Group Name",
  "description": "Group description",
  "category": "general",
  "is_private": false,
  "avatar_url": "https://cdn.sojorn.app/groups/uuid.jpg",
  "banner_url": "https://cdn.sojorn.app/groups/banner/uuid.jpg"
}
```

**Response:**
```json
{
  "success": true,
  "group": {
    "id": "uuid",
    "name": "Group Name",
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

---

## 🔐 E2EE Chat

### POST /e2ee/register-device
Register a device for E2EE chat.

**Request:**
```json
{
  "device_name": "iPhone 14",
  "device_type": "mobile",
  "public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
}
```

**Response:**
```json
{
  "success": true,
  "device": {
    "id": "device_uuid",
    "name": "iPhone 14",
    "type": "mobile",
    "public_key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### POST /e2ee/send-message
Send an encrypted message.

**Request:**
```json
{
  "recipient_id": "uuid",
  "message": "encrypted_message_here",
  "is_encrypted": true
}
```

**Response:**
```json
{
  "success": true,
  "message": {
    "id": "uuid",
    "sender_id": "uuid",
    "recipient_id": "uuid",
    "message": "encrypted_message_here",
    "is_encrypted": true,
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### GET /e2ee/messages/{user_id}
Get encrypted messages with a user.

**Response:**
```json
{
  "success": true,
  "messages": [
    {
      "id": "uuid",
      "sender_id": "uuid",
      "recipient_id": "uuid",
      "message": "encrypted_message_here",
      "is_encrypted": true,
      "created_at": "2026-02-17T12:00:00Z"
    }
  ]
}
```

---

## 🎬 Video (Quips)

### POST /videos/upload
Upload and process a video.

**Request (multipart/form-data):**
```
video: [video file]
thumbnail: [thumbnail file]
title: "Video Title"
description: "Video description"
duration: 30
```

**Response:**
```json
{
  "success": true,
  "video": {
    "id": "uuid",
    "url": "https://cdn.sojorn.app/videos/uuid.mp4",
    "thumbnail_url": "https://cdn.sojorn.app/thumbnails/uuid.jpg",
    "title": "Video Title",
    "description": "Video description",
    "duration": 30,
    "created_at": "2026-02-17T12:00:00Z"
  }
}
```

### POST /videos/process
Process video with effects.

**Request:**
```json
{
  "video_id": "uuid",
  "filter": "vintage",
  "speed": 1.5,
  "text_overlays": [
    {
      "text": "Hello World",
      "x": 100,
      "y": 100,
      "start_time": 5,
      "end_time": 10
    }
  ],
  "audio_track": {
    "url": "https://cdn.sojorn.app/audio/uuid.mp3",
    "volume": 0.5,
    "fade_in": true,
    "fade_out": true
  }
}
```

**Response:**
```json
{
  "success": true,
  "processed_video": {
    "url": "https://cdn.sojorn.app/videos/processed/uuid.mp4",
    "processing_time": 15.5
  }
}
```

---

## 🤖 AI Moderation

### POST /moderation/analyze
Analyze content for moderation.

**Request:**
```json
{
  "content": "Content to analyze",
  "type": "text",
  "image_url": "https://cdn.sojorn.app/images/uuid.jpg",
  "video_url": "https://cdn.sojorn.app/videos/uuid.mp4"
}
```

**Response:**
```json
{
  "success": true,
  "analysis": {
    "is_safe": true,
    "score": 0.95,
    "categories": {
      "hate": 0.1,
      "greed": 0.05,
      "delusion": 0.02
    },
    "recommendation": "approve",
    "confidence": 0.98
  }
}
```

---

## 🚫 Blocking System

### GET /users/me/blocked
Get blocked users list.

**Response:**
```json
{
  "success": true,
  "blocked_users": [
    {
      "id": "uuid",
      "handle": "blocked_user",
      "display_name": "Blocked User",
      "blocked_at": "2026-02-17T12:00:00Z"
    }
  ],
  "total": 5
}
```

### POST /users/{id}/block
Block a user.

**Response:**
```json
{
  "success": true,
  "message": "User blocked successfully"
}
```

### DELETE /users/{id}/block
Unblock a user.

**Response:**
```json
{
  "success": true,
  "message": "User unblocked successfully"
}
```

### POST /users/me/blocked/import
Import blocked users from other platforms.

**Request:**
```json
{
  "platform": "twitter",
  "data": "username1,username2,username3"
}
```

**Response:**
```json
{
  "success": true,
  "imported": 3,
  "skipped": 0,
  "failed": 0
}
```

---

## 📊 Analytics & Metrics

### GET /analytics/feed
Get feed analytics.

**Query Parameters:**
- `date_range`: 7d, 30d, 90d
- `category`: Filter by category

**Response:**
```json
{
  "success": true,
  "analytics": {
    "total_posts": 1000,
    "total_engagement": 5000,
    "engagement_rate": 0.05,
    "top_categories": [
      {"category": "general", "count": 400},
      {"category": "hobby", "count": 300}
    ],
    "daily_stats": [
      {
        "date": "2026-02-17",
        "posts": 50,
        "engagement": 250
      }
    ]
  }
}
```

---

## 🔍 Search

### GET /search
Search across the platform.

**Query Parameters:**
- `q`: Search query
- `type`: posts, users, groups, beacons
- `limit`: Number of results (default: 20)
- `offset`: Pagination offset

**Response:**
```json
{
  "success": true,
  "results": {
    "posts": [
      {
        "id": "uuid",
        "body": "Post containing search term",
        "author_handle": "username",
        "created_at": "2026-02-17T12:00:00Z"
      }
    ],
    "users": [
      {
        "id": "uuid",
        "handle": "username",
        "display_name": "Display Name",
        "bio": "Bio containing search term"
      }
    ],
    "groups": [
      {
        "id": "uuid",
        "name": "Group Name",
        "description": "Description containing search term"
      }
    ],
    "beacons": [
      {
        "id": "uuid",
        "title": "Beacon Title",
        "description": "Description containing search term"
      }
    ]
  }
}
```

---

## 📱 Notifications

### GET /notifications
Get user notifications.

**Query Parameters:**
- `limit`: Number of notifications (default: 50)
- `offset`: Pagination offset
- `type`: Filter by notification type
- `unread_only`: Filter for unread only

**Response:**
```json
{
  "success": true,
  "notifications": [
    {
      "id": "uuid",
      "type": "like",
      "title": "New Like",
      "body": "username liked your post",
      "data": {
        "post_id": "uuid",
        "user_id": "uuid"
      },
      "is_read": false,
      "created_at": "2026-02-17T12:00:00Z"
    }
  ],
  "unread_count": 5,
  "pagination": {
    "total": 100,
    "limit": 50,
    "offset": 0,
    "has_more": true
  }
}
```

### POST /notifications/{id}/read
Mark notification as read.

**Response:**
```json
{
  "success": true,
  "message": "Notification marked as read"
}
```

---

## ⚙️ Settings & Preferences

### GET /users/me/settings
Get user settings.

**Response:**
```json
{
  "success": true,
  "settings": {
    "notifications": {
      "push_enabled": true,
      "email_enabled": true,
      "likes": true,
      "comments": true,
      "follows": true,
      "mentions": true
    },
    "privacy": {
      "profile_visibility": "public",
      "show_online_status": true,
      "allow_tagging": true,
      "nsfw_blur_enabled": true
    },
    "feed": {
      "algorithm_enabled": true,
      "show_suggested_posts": true,
      "hide_sensitive_content": true
    }
  }
}
```

### PUT /users/me/settings
Update user settings.

**Request:**
```json
{
  "notifications": {
    "push_enabled": true,
    "email_enabled": false,
    "likes": true,
    "comments": false,
    "follows": true,
    "mentions": true
  },
  "privacy": {
    "profile_visibility": "public",
    "show_online_status": false,
    "allow_tagging": true,
    "nsfw_blur_enabled": true
  }
}
```

**Response:**
```json
{
  "success": true,
  "settings": {
    "notifications": {
      "push_enabled": true,
      "email_enabled": false,
      "likes": true,
      "comments": false,
      "follows": true,
      "mentions": true
    },
    "privacy": {
      "profile_visibility": "public",
      "show_online_status": false,
      "allow_tagging": true,
      "nsfw_blur_enabled": true
    }
  }
}
```

---

## 🏥 Health & Monitoring

### GET /health
System health check.

**Response:**
```json
{
  "status": "healthy",
  "timestamp": "2026-02-17T12:00:00Z",
  "uptime": "72h30m15s",
  "version": "3.0.0",
  "environment": "production",
  "checks": {
    "database": {
      "status": "healthy",
      "message": "Database connection successful",
      "duration": "5ms"
    },
    "redis": {
      "status": "healthy",
      "message": "Redis connection successful",
      "duration": "2ms"
    },
    "storage": {
      "status": "healthy",
      "message": "Cloudflare R2 accessible",
      "duration": "150ms"
    }
  }
}
```

### GET /metrics
Application metrics.

**Response:**
```json
{
  "success": true,
  "metrics": {
    "requests": {
      "total": 1000000,
      "per_second": 50,
      "error_rate": 0.01
    },
    "database": {
      "connections": 25,
      "queries_per_second": 100,
      "avg_response_time": "25ms"
    },
    "memory": {
      "used_mb": 512,
      "available_mb": 1536,
      "usage_percent": 25
    },
    "cpu": {
      "usage_percent": 15,
      "load_average": [0.5, 0.6, 0.7]
    }
  }
}
```

---

## 📚 Error Responses

All endpoints return consistent error responses:

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": {
      "field": "email",
      "issue": "Invalid email format"
    }
  }
}
```

### Common Error Codes

- `UNAUTHORIZED`: Authentication required or invalid
- `FORBIDDEN`: Insufficient permissions
- `NOT_FOUND`: Resource not found
- `VALIDATION_ERROR`: Invalid input data
- `RATE_LIMITED`: Too many requests
- `INTERNAL_ERROR`: Server error
- `SERVICE_UNAVAILABLE`: Service temporarily unavailable

---

## 📝 Rate Limiting

API endpoints are rate limited to prevent abuse:

- **Authentication**: 5 requests per minute
- **Content Creation**: 10 requests per minute
- **Search**: 30 requests per minute
- **General**: 100 requests per minute

Rate limit headers are included in responses:
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1645123200
```

---

## 🔑 API Keys

For service-to-service integration, generate API keys in the admin panel:

```bash
# Example API key usage
curl -H "X-API-Key: your-api-key-here" \
     -H "Content-Type: application/json" \
     https://api.sojorn.app/posts
```

---

## 📞 Support

### Documentation
- **API Reference**: Complete endpoint documentation
- **SDKs**: Official SDKs for popular languages
- **Examples**: Code examples and tutorials
- **Changelog**: API version history and changes

### Support Channels
- **Discord**: API development discussion
- **GitHub**: Issue tracking and feature requests
- **Email**: api-support@sojorn.app
- **Status**: api.sojorn.app/status

---

**🚀 The Sojorn API provides comprehensive, production-ready endpoints for all platform features with proper authentication, rate limiting, and error handling.**
