- Updated backend README.md to include detailed management commands for configuration, database operations, cache management, data management, user authentication, content/media handling, trending/discovery, testing/development, and security/auditing. - Added a new MANAGEMENT_COMMANDS.md file for comprehensive command reference. - Included logging standardization details in architecture documentation (ADR-007). - Improved production checklist with configuration validation and cache verification steps. - Expanded API documentation to include error logging details. - Created a documentation review checklist to ensure completeness and accuracy.
42 KiB
ThrillWiki API Documentation v1
Complete Frontend Developer Reference
Base URL: /api/v1/
Authentication: JWT Bearer tokens
Content-Type: application/json
🔑 Authentication Requirements
JWT Authentication
Most endpoints require authentication via JWT Bearer tokens. Include the token in the Authorization header:
Authorization: Bearer <access_token>
Token Lifetime
- Access Token: 15 minutes (configurable via
JWT_ACCESS_TOKEN_LIFETIME_MINUTES) - Refresh Token: 7 days (configurable via
JWT_REFRESH_TOKEN_LIFETIME_DAYS)
Unauthenticated Access
The following endpoints allow unauthenticated access:
GET /parks/- List parksGET /parks/<pk>/- Park detailsGET /rides/- List ridesGET /rides/<pk>/- Ride detailsGET /parks/<pk>/photos/- Park photos listGET /rides/<pk>/photos/- Ride photos listPOST /auth/login/- User loginPOST /auth/signup/- User registrationPOST /auth/password/reset/- Password reset requestGET /auth/social/providers/- Available social providers
⏱️ Rate Limiting
Rate limits are enforced per user/IP to prevent abuse:
| User Type | Limit |
|---|---|
| Anonymous | 60 requests/minute |
| Authenticated | 1000 requests/hour |
Rate Limit Headers
Responses include rate limit information in headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1703347200
Rate Limit Exceeded Response
{
"error": "Request was throttled",
"error_code": "RATE_LIMIT_EXCEEDED",
"detail": "Expected available in 60 seconds."
}
📄 Pagination
List endpoints use page-based pagination:
Query Parameters
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
page |
int | 1 | - | Page number |
page_size |
int | 20 | 100 | Results per page |
Paginated Response Format
{
"count": 150,
"next": "https://api.thrillwiki.com/api/v1/parks/?page=2",
"previous": null,
"results": [...]
}
🔐 Authentication Endpoints (/api/v1/auth/)
POST /auth/login/ - User Login
Authenticate a user and receive JWT tokens.
Request Body:
{
"username": "johndoe",
"password": "securepassword123"
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/login/ \
-H "Content-Type: application/json" \
-d '{"username": "johndoe", "password": "securepassword123"}'
Success Response (200 OK):
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user": {
"id": 42,
"username": "johndoe",
"email": "johndoe@example.com",
"display_name": "John Doe",
"avatar_url": "https://imagedelivery.net/xxx/avatar.jpg"
}
}
Error Response (400 Bad Request):
{
"error": "Invalid credentials",
"error_code": "INVALID_CREDENTIALS",
"details": {
"non_field_errors": ["Unable to log in with provided credentials."]
}
}
POST /auth/signup/ - User Registration
Register a new user account. Email verification is required before full access.
Request Body:
{
"username": "newuser",
"email": "newuser@example.com",
"password1": "ComplexPass123!",
"password2": "ComplexPass123!"
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/signup/ \
-H "Content-Type: application/json" \
-d '{"username": "newuser", "email": "newuser@example.com", "password1": "ComplexPass123!", "password2": "ComplexPass123!"}'
Success Response (201 Created):
{
"success": true,
"message": "Verification email sent. Please check your inbox.",
"user": {
"id": 43,
"username": "newuser",
"email": "newuser@example.com"
}
}
Error Response (400 Bad Request):
{
"error": "Validation failed",
"error_code": "VALIDATION_ERROR",
"details": {
"username": ["A user with that username already exists."],
"password1": ["This password is too common."]
}
}
POST /auth/logout/ - User Logout
Logout the current user and blacklist the refresh token.
Authentication: Required
Request Body (optional):
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/logout/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"refresh": "<refresh_token>"}'
Success Response (200 OK):
{
"message": "Successfully logged out."
}
GET /auth/user/ - Get Current User
Retrieve the authenticated user's information.
Authentication: Required
curl Example:
curl -X GET https://api.thrillwiki.com/api/v1/auth/user/ \
-H "Authorization: Bearer <access_token>"
Success Response (200 OK):
{
"id": 42,
"username": "johndoe",
"email": "johndoe@example.com",
"display_name": "John Doe",
"date_joined": "2024-01-15T10:30:00Z",
"is_active": true,
"avatar_url": "https://imagedelivery.net/xxx/avatar.jpg"
}
POST /auth/status/ - Check Authentication Status
Check if the current request is authenticated.
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/status/ \
-H "Authorization: Bearer <access_token>"
Authenticated Response (200 OK):
{
"authenticated": true,
"user": {
"id": 42,
"username": "johndoe"
}
}
Unauthenticated Response (200 OK):
{
"authenticated": false
}
POST /auth/password/reset/ - Request Password Reset
Request a password reset email.
Request Body:
{
"email": "johndoe@example.com"
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/password/reset/ \
-H "Content-Type: application/json" \
-d '{"email": "johndoe@example.com"}'
Success Response (200 OK):
{
"message": "Password reset email sent."
}
Note: For security, this endpoint always returns success, regardless of whether the email exists.
POST /auth/password/change/ - Change Password
Change the authenticated user's password.
Authentication: Required
Request Body:
{
"old_password": "currentpassword",
"new_password1": "NewComplexPass123!",
"new_password2": "NewComplexPass123!"
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/password/change/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"old_password": "currentpassword", "new_password1": "NewComplexPass123!", "new_password2": "NewComplexPass123!"}'
Success Response (200 OK):
{
"message": "Password changed successfully."
}
POST /auth/token/refresh/ - Refresh Access Token
Obtain a new access token using a refresh token.
Request Body:
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/auth/token/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh": "<refresh_token>"}'
Success Response (200 OK):
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
Note: Refresh tokens are rotated on each use. The old refresh token is blacklisted.
GET /auth/social/providers/ - Get Social Providers
List available social authentication providers.
curl Example:
curl -X GET https://api.thrillwiki.com/api/v1/auth/social/providers/
Success Response (200 OK):
[
{
"provider": "google",
"name": "Google",
"enabled": true
},
{
"provider": "discord",
"name": "Discord",
"enabled": true
}
]
Email Verification Endpoints
- GET
/auth/verify-email/<token>/- Verify email with token - POST
/auth/resend-verification/- Resend email verification
Social Authentication Endpoints
- GET
/auth/social/providers/available/- Get available social providers list - GET
/auth/social/connected/- Get user's connected social providers (auth required) - POST
/auth/social/connect/<provider>/- Connect social provider (auth required) - POST
/auth/social/disconnect/<provider>/- Disconnect social provider (auth required) - GET
/auth/social/status/- Get comprehensive social auth status (auth required)
🏞️ Parks API Endpoints (/api/v1/parks/)
GET /parks/hybrid/ - List Parks with Hybrid Filtering
Retrieve parks with intelligent hybrid filtering strategy. This endpoint provides optimal performance by selecting between database and client-side filtering based on the query.
Authentication: Optional
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Search by park name |
status |
string | Filter by status (OPERATING, CLOSED_PERM, UNDER_CONSTRUCTION) |
continent |
string | Filter by continent code |
country |
string | Filter by country code |
state |
string | Filter by state/province |
operator_slug |
string | Filter by operator slug |
rating_min |
float | Minimum rating (0-10) |
rating_max |
float | Maximum rating (0-10) |
opening_year_min |
int | Minimum opening year |
opening_year_max |
int | Maximum opening year |
coaster_count_min |
int | Minimum roller coaster count |
coaster_count_max |
int | Maximum roller coaster count |
offset |
int | Pagination offset for progressive loading |
ordering |
string | Sort field (name, -name, rating, -rating) |
curl Example:
# List operating parks in North America with rating >= 7
curl -X GET "https://api.thrillwiki.com/api/v1/parks/hybrid/?status=OPERATING&continent=NA&rating_min=7"
Success Response (200 OK):
{
"success": true,
"data": {
"parks": [
{
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point",
"description": "The Roller Coaster Capital of the World",
"status": "OPERATING",
"park_type": "THEME",
"opening_year": 1870,
"location": {
"continent": "NA",
"country": "US",
"state": "OH",
"city": "Sandusky",
"latitude": 41.4784,
"longitude": -82.6775
},
"operator": {
"id": 5,
"name": "Cedar Fair",
"slug": "cedar-fair"
},
"statistics": {
"ride_count": 72,
"roller_coaster_count": 17,
"average_rating": 9.2
},
"image_url": "https://imagedelivery.net/xxx/park-main.jpg"
}
],
"total_count": 45,
"has_more": true,
"strategy": "database",
"filter_metadata": {
"statuses": ["OPERATING", "CLOSED_PERM", "UNDER_CONSTRUCTION"],
"continents": ["NA", "EU", "AS", "SA", "OC", "AF"]
}
}
}
GET /parks/<pk>/ - Get Park Details
Retrieve detailed information about a specific park by ID or slug.
Authentication: Optional
curl Example:
curl -X GET https://api.thrillwiki.com/api/v1/parks/cedar-point/
Success Response (200 OK):
{
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point",
"description": "The Roller Coaster Capital of the World, featuring world-class thrill rides.",
"status": "OPERATING",
"park_type": "THEME",
"opening_year": 1870,
"website": "https://www.cedarpoint.com",
"location": {
"address": "1 Cedar Point Drive",
"city": "Sandusky",
"state": "OH",
"country": "US",
"continent": "NA",
"postal_code": "44870",
"latitude": 41.4784,
"longitude": -82.6775
},
"operator": {
"id": 5,
"name": "Cedar Fair",
"slug": "cedar-fair"
},
"property_owner": {
"id": 5,
"name": "Cedar Fair",
"slug": "cedar-fair"
},
"statistics": {
"ride_count": 72,
"roller_coaster_count": 17,
"flat_ride_count": 32,
"water_ride_count": 8,
"average_rating": 9.2,
"review_count": 1523
},
"images": {
"primary": "https://imagedelivery.net/xxx/park-main.jpg",
"gallery": [
"https://imagedelivery.net/xxx/park-1.jpg",
"https://imagedelivery.net/xxx/park-2.jpg"
]
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-12-15T14:30:00Z"
}
Error Response (404 Not Found):
{
"error": "Park not found",
"error_code": "NOT_FOUND",
"details": {
"message": "No park exists with the given identifier."
}
}
POST /parks/ - Create Park
Create a new park entry.
Authentication: Required
Request Body:
{
"name": "New Theme Park",
"description": "An exciting new theme park opening soon.",
"status": "UNDER_CONSTRUCTION",
"park_type": "THEME",
"opening_year": 2025,
"operator_id": 5,
"location": {
"city": "Orlando",
"state": "FL",
"country": "US",
"latitude": 28.3772,
"longitude": -81.5707
}
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/parks/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"name": "New Theme Park", "status": "UNDER_CONSTRUCTION", "park_type": "THEME"}'
Success Response (201 Created):
{
"success": true,
"data": {
"id": 156,
"name": "New Theme Park",
"slug": "new-theme-park",
"status": "UNDER_CONSTRUCTION"
},
"message": "Park created successfully."
}
POST /parks/<park_pk>/photos/ - Upload Park Photo
Upload a photo for a park.
Authentication: Required
Content-Type: multipart/form-data
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/parks/1/photos/ \
-H "Authorization: Bearer <access_token>" \
-F "image=@/path/to/photo.jpg" \
-F "caption=Beautiful entrance view" \
-F "photo_type=GENERAL"
Success Response (201 Created):
{
"id": 523,
"image_url": "https://imagedelivery.net/xxx/photo.jpg",
"caption": "Beautiful entrance view",
"photo_type": "GENERAL",
"is_primary": false,
"is_approved": false,
"uploaded_by": {
"id": 42,
"username": "johndoe"
},
"created_at": "2024-12-20T10:30:00Z"
}
POST /parks/<park_pk>/photos/bulk_approve/ - Bulk Approve Photos (Admin)
Bulk approve or reject multiple photos at once.
Authentication: Required (Staff only)
Request Body:
{
"photo_ids": [523, 524, 525],
"approve": true
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/parks/1/photos/bulk_approve/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"photo_ids": [523, 524, 525], "approve": true}'
Success Response (200 OK):
{
"success": true,
"message": "3 photos approved successfully.",
"processed": 3
}
Error Response (403 Forbidden):
{
"error": "Permission denied",
"error_code": "FORBIDDEN",
"details": {
"message": "Staff privileges required for bulk operations."
}
}
GET /parks/filter-metadata/ - Get Filter Metadata
Retrieve available filter options and value ranges for park filtering.
curl Example:
curl -X GET https://api.thrillwiki.com/api/v1/parks/filter-metadata/
Success Response (200 OK):
{
"success": true,
"data": {
"categorical": {
"statuses": [
{"value": "OPERATING", "label": "Operating", "count": 2500},
{"value": "CLOSED_PERM", "label": "Permanently Closed", "count": 850},
{"value": "UNDER_CONSTRUCTION", "label": "Under Construction", "count": 45}
],
"park_types": [
{"value": "THEME", "label": "Theme Park", "count": 1200},
{"value": "AMUSEMENT", "label": "Amusement Park", "count": 1800}
],
"continents": [
{"value": "NA", "label": "North America", "count": 1100},
{"value": "EU", "label": "Europe", "count": 900}
]
},
"ranges": {
"opening_year": {"min": 1843, "max": 2025},
"rating": {"min": 0, "max": 10},
"ride_count": {"min": 0, "max": 150},
"coaster_count": {"min": 0, "max": 20}
},
"total_count": 3395
}
}
Additional Parks Endpoints
Search & Filtering
- GET
/parks/filter-options/- Get available filter options (legacy) - GET
/parks/search/companies/?q=<query>- Search companies/operators - GET
/parks/search-suggestions/?q=<query>- Get park search suggestions
Park Photos
- GET
/parks/<park_pk>/photos/- List park photos - GET
/parks/<park_pk>/photos/<id>/- Get park photo details - PATCH
/parks/<park_pk>/photos/<id>/- Update park photo (auth required) - DELETE
/parks/<park_pk>/photos/<id>/- Delete park photo (auth required) - POST
/parks/<park_pk>/photos/<id>/set_primary/- Set photo as primary (auth required) - GET
/parks/<park_pk>/photos/stats/- Get park photo statistics
Park Settings
- GET
/parks/<pk>/image-settings/- Get park image settings - POST
/parks/<pk>/image-settings/- Update park image settings
🎢 Rides API Endpoints (/api/v1/rides/)
GET /rides/hybrid/ - List Rides with Hybrid Filtering
Retrieve rides with intelligent filtering. Similar to parks, this endpoint uses hybrid strategy for optimal performance.
Authentication: Optional
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search |
string | Search by ride name |
park |
string | Filter by park slug |
category |
string | Filter by category (RC, DR, FR, WR, TR, OT) |
manufacturer_slug |
string | Filter by manufacturer |
status |
string | Filter by status |
speed_min |
float | Minimum speed (mph) |
speed_max |
float | Maximum speed (mph) |
height_min |
float | Minimum height (ft) |
height_max |
float | Maximum height (ft) |
opening_year_min |
int | Minimum opening year |
opening_year_max |
int | Maximum opening year |
ordering |
string | Sort field |
curl Example:
# List roller coasters at Cedar Point
curl -X GET "https://api.thrillwiki.com/api/v1/rides/hybrid/?park=cedar-point&category=RC"
Success Response (200 OK):
{
"success": true,
"data": {
"rides": [
{
"id": 42,
"name": "Steel Vengeance",
"slug": "steel-vengeance",
"category": "RC",
"category_display": "Roller Coaster",
"status": "OPERATING",
"opening_year": 2018,
"park": {
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point"
},
"manufacturer": {
"id": 10,
"name": "Rocky Mountain Construction",
"slug": "rocky-mountain-construction"
},
"statistics": {
"height_ft": 205,
"speed_mph": 74,
"length_ft": 5740,
"inversions": 4,
"average_rating": 9.8
},
"image_url": "https://imagedelivery.net/xxx/ride.jpg"
}
],
"total_count": 17,
"has_more": false,
"strategy": "database"
}
}
GET /rides/<pk>/ - Get Ride Details
Retrieve detailed information about a specific ride.
Authentication: Optional
curl Example:
curl -X GET https://api.thrillwiki.com/api/v1/rides/steel-vengeance/
Success Response (200 OK):
{
"id": 42,
"name": "Steel Vengeance",
"slug": "steel-vengeance",
"description": "A record-breaking hybrid coaster built on the bones of Mean Streak.",
"category": "RC",
"category_display": "Roller Coaster",
"status": "OPERATING",
"opening_year": 2018,
"park": {
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point"
},
"manufacturer": {
"id": 10,
"name": "Rocky Mountain Construction",
"slug": "rocky-mountain-construction"
},
"ride_model": {
"id": 15,
"name": "IBox Track Conversion",
"slug": "ibox-track-conversion"
},
"specifications": {
"height_ft": 205,
"drop_ft": 200,
"speed_mph": 74,
"length_ft": 5740,
"duration_seconds": 150,
"inversions": 4,
"capacity_per_hour": 1200,
"min_height_inches": 52
},
"statistics": {
"average_rating": 9.8,
"review_count": 2847,
"ranking_position": 1
},
"images": {
"primary": "https://imagedelivery.net/xxx/ride-main.jpg",
"gallery": [
"https://imagedelivery.net/xxx/ride-1.jpg"
]
},
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-12-15T14:30:00Z"
}
POST /rides/ - Create Ride
Create a new ride entry.
Authentication: Required
Request Body:
{
"name": "New Coaster",
"category": "RC",
"status": "UNDER_CONSTRUCTION",
"park_id": 1,
"manufacturer_id": 10,
"opening_year": 2025,
"specifications": {
"height_ft": 300,
"speed_mph": 90
}
}
curl Example:
curl -X POST https://api.thrillwiki.com/api/v1/rides/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"name": "New Coaster", "category": "RC", "park_id": 1}'
Success Response (201 Created):
{
"success": true,
"data": {
"id": 1523,
"name": "New Coaster",
"slug": "new-coaster",
"category": "RC"
},
"message": "Ride created successfully."
}
Ride Category Codes
| Code | Category |
|---|---|
RC |
Roller Coaster |
DR |
Dark Ride |
FR |
Flat Ride |
WR |
Water Ride |
TR |
Transport Ride |
OT |
Other |
Additional Rides Endpoints
Search & Filtering
- GET
/rides/filter-options/- Get available filter options - GET
/rides/search/companies/?q=<query>- Search ride companies - GET
/rides/search/ride-models/?q=<query>- Search ride models - GET
/rides/search-suggestions/?q=<query>- Get ride search suggestions - GET
/rides/hybrid/filter-metadata/- Get ride filter metadata
Ride Photos
- GET
/rides/<ride_pk>/photos/- List ride photos - POST
/rides/<ride_pk>/photos/- Upload ride photo (auth required) - GET
/rides/<ride_pk>/photos/<id>/- Get ride photo details - PATCH
/rides/<ride_pk>/photos/<id>/- Update ride photo (auth required) - DELETE
/rides/<ride_pk>/photos/<id>/- Delete ride photo (auth required) - POST
/rides/<ride_pk>/photos/<id>/set_primary/- Set photo as primary (auth required)
Ride Manufacturers
- GET
/rides/manufacturers/<manufacturer_slug>/- List manufacturer's rides
Ride Settings
- GET
/rides/<pk>/image-settings/- Get ride image settings - POST
/rides/<pk>/image-settings/- Update ride image settings
👤 User Accounts API (/api/v1/accounts/)
User Management (Admin)
- DELETE
/accounts/users/<user_id>/delete/- Delete user while preserving submissions - GET
/accounts/users/<user_id>/deletion-check/- Check user deletion eligibility
Self-Service Account Management
- POST
/accounts/delete-account/request/- Request account deletion - POST
/accounts/delete-account/verify/- Verify account deletion - POST
/accounts/delete-account/cancel/- Cancel account deletion
User Profile Management
- GET
/accounts/profile/- Get user profile - PATCH
/accounts/profile/account/- Update user account info - PATCH
/accounts/profile/update/- Update user profile
User Preferences
- GET
/accounts/preferences/- Get user preferences - PATCH
/accounts/preferences/update/- Update user preferences - PATCH
/accounts/preferences/theme/- Update theme preference
Settings Management
- GET
/accounts/settings/notifications/- Get notification settings - PATCH
/accounts/settings/notifications/update/- Update notification settings - GET
/accounts/settings/privacy/- Get privacy settings - PATCH
/accounts/settings/privacy/update/- Update privacy settings - GET
/accounts/settings/security/- Get security settings - PATCH
/accounts/settings/security/update/- Update security settings
User Statistics & Lists
- GET
/accounts/statistics/- Get user statistics - GET
/accounts/top-lists/- Get user's top lists - POST
/accounts/top-lists/create/- Create new top list - PATCH
/accounts/top-lists/<list_id>/- Update top list - DELETE
/accounts/top-lists/<list_id>/delete/- Delete top list
Notifications
- GET
/accounts/notifications/- Get user notifications - POST
/accounts/notifications/mark-read/- Mark notifications as read - GET
/accounts/notification-preferences/- Get notification preferences - PATCH
/accounts/notification-preferences/update/- Update notification preferences
Avatar Management
- POST
/accounts/profile/avatar/upload/- Upload avatar - POST
/accounts/profile/avatar/save/- Save avatar image - DELETE
/accounts/profile/avatar/delete/- Delete avatar
🗺️ Maps API (/api/v1/maps/)
Location Data
- GET
/maps/locations/- Get map locations data - GET
/maps/locations/<location_type>/<location_id>/- Get location details - GET
/maps/search/- Search locations on map - GET
/maps/bounds/- Query locations within bounds
Map Services
- GET
/maps/stats/- Get map service statistics - GET
/maps/cache/- Get map cache information - POST
/maps/cache/invalidate/- Invalidate map cache
🔍 Core Search API (/api/v1/core/)
Entity Search
- GET
/core/entities/search/- Fuzzy search for entities - GET
/core/entities/not-found/- Handle entity not found - GET
/core/entities/suggestions/- Quick entity suggestions
📧 Email API (/api/v1/email/)
Email Services
- POST
/email/send/- Send email
📜 History API (/api/v1/history/)
Park History
- GET
/history/parks/<park_slug>/- Get park history - GET
/history/parks/<park_slug>/detail/- Get detailed park history
Ride History
- GET
/history/parks/<park_slug>/rides/<ride_slug>/- Get ride history - GET
/history/parks/<park_slug>/rides/<ride_slug>/detail/- Get detailed ride history
Unified Timeline
- GET
/history/timeline/- Get unified history timeline
📈 System & Analytics APIs
Health Checks
- GET
/api/v1/health/- Comprehensive health check - GET
/api/v1/health/simple/- Simple health check - GET
/api/v1/health/performance/- Performance metrics
Trending & Discovery
- GET
/api/v1/trending/- Get trending content - GET
/api/v1/new-content/- Get new content - POST
/api/v1/trending/calculate/- Trigger trending calculation
Statistics
- GET
/api/v1/stats/- Get system statistics - POST
/api/v1/stats/recalculate/- Recalculate statistics
Reviews
- GET
/api/v1/reviews/latest/- Get latest reviews
Rankings
- GET
/api/v1/rankings/- Get ride rankings with filtering - GET
/api/v1/rankings/<ride_slug>/- Get detailed ranking for specific ride - GET
/api/v1/rankings/<ride_slug>/history/- Get ranking history for ride - GET
/api/v1/rankings/<ride_slug>/comparisons/- Get head-to-head comparisons - GET
/api/v1/rankings/statistics/- Get ranking system statistics - POST
/api/v1/rankings/calculate/- Trigger ranking calculation (admin)
Rankings Filtering Parameters:
- category: Filter by ride category (RC, DR, FR, WR, TR, OT)
- min_riders: Minimum number of mutual riders required
- park: Filter by park slug
- ordering: Order results (rank, -rank, winning_percentage, -winning_percentage)
🛡️ Moderation API (/api/v1/moderation/)
Moderation Reports
- GET
/moderation/reports/- List all moderation reports - POST
/moderation/reports/- Create new moderation report - GET
/moderation/reports/<id>/- Get specific report details - PUT
/moderation/reports/<id>/- Update moderation report - PATCH
/moderation/reports/<id>/- Partial update report - DELETE
/moderation/reports/<id>/- Delete moderation report - POST
/moderation/reports/<id>/assign/- Assign report to moderator - POST
/moderation/reports/<id>/resolve/- Resolve moderation report - GET
/moderation/reports/stats/- Get report statistics
Moderation Queue
- GET
/moderation/queue/- List moderation queue items - POST
/moderation/queue/- Create queue item - GET
/moderation/queue/<id>/- Get specific queue item - PUT
/moderation/queue/<id>/- Update queue item - PATCH
/moderation/queue/<id>/- Partial update queue item - DELETE
/moderation/queue/<id>/- Delete queue item - POST
/moderation/queue/<id>/assign/- Assign queue item to moderator - POST
/moderation/queue/<id>/unassign/- Unassign queue item - POST
/moderation/queue/<id>/complete/- Complete queue item - GET
/moderation/queue/my_queue/- Get current user's queue items
Moderation Actions
- GET
/moderation/actions/- List all moderation actions - POST
/moderation/actions/- Create new moderation action - GET
/moderation/actions/<id>/- Get specific action details - PUT
/moderation/actions/<id>/- Update moderation action - PATCH
/moderation/actions/<id>/- Partial update action - DELETE
/moderation/actions/<id>/- Delete moderation action - POST
/moderation/actions/<id>/deactivate/- Deactivate action - GET
/moderation/actions/active/- Get active moderation actions - GET
/moderation/actions/expired/- Get expired moderation actions
Bulk Operations
- GET
/moderation/bulk-operations/- List bulk moderation operations - POST
/moderation/bulk-operations/- Create bulk operation - GET
/moderation/bulk-operations/<id>/- Get bulk operation details - PUT
/moderation/bulk-operations/<id>/- Update bulk operation - PATCH
/moderation/bulk-operations/<id>/- Partial update operation - DELETE
/moderation/bulk-operations/<id>/- Delete bulk operation - POST
/moderation/bulk-operations/<id>/cancel/- Cancel bulk operation - POST
/moderation/bulk-operations/<id>/retry/- Retry failed operation - GET
/moderation/bulk-operations/<id>/logs/- Get operation logs - GET
/moderation/bulk-operations/running/- Get running operations
User Moderation
- GET
/moderation/users/<id>/- Get user moderation profile - POST
/moderation/users/<id>/moderate/- Take moderation action against user - GET
/moderation/users/search/- Search users for moderation - GET
/moderation/users/stats/- Get user moderation statistics
🏗️ Ride Manufacturers & Models (/api/v1/rides/manufacturers/<manufacturer_slug>/)
Ride Models
- GET
/rides/manufacturers/<manufacturer_slug>/- List ride models by manufacturer - POST
/rides/manufacturers/<manufacturer_slug>/- Create new ride model - GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/- Get ride model details - PATCH
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/- Update ride model - DELETE
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/- Delete ride model
Model Search & Filtering
- GET
/rides/manufacturers/<manufacturer_slug>/search/- Search ride models - GET
/rides/manufacturers/<manufacturer_slug>/filter-options/- Get filter options - GET
/rides/manufacturers/<manufacturer_slug>/stats/- Get manufacturer statistics
Model Variants
- GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/variants/- List model variants - POST
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/variants/- Create variant - GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/variants/<id>/- Get variant details - PATCH
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/variants/<id>/- Update variant - DELETE
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/variants/<id>/- Delete variant
Technical Specifications
- GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/technical-specs/- List technical specs - POST
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/technical-specs/- Create technical spec - GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/technical-specs/<id>/- Get spec details - PATCH
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/technical-specs/<id>/- Update spec - DELETE
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/technical-specs/<id>/- Delete spec
Model Photos
- GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/photos/- List model photos - POST
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/photos/- Upload model photo - GET
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/photos/<id>/- Get photo details - PATCH
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/photos/<id>/- Update photo - DELETE
/rides/manufacturers/<manufacturer_slug>/<ride_model_slug>/photos/<id>/- Delete photo
🖼️ Media Management
Cloudflare Images
- ALL
/api/v1/cloudflare-images/- Cloudflare Images toolkit endpoints
📚 API Documentation
Interactive Documentation
- GET
/api/schema/- OpenAPI schema - GET
/api/docs/- Swagger UI documentation - GET
/api/redoc/- ReDoc documentation
🔧 Common Request/Response Patterns
Authentication Headers
headers: {
'Authorization': 'Bearer <access_token>',
'Content-Type': 'application/json'
}
Pagination Response
{
"count": 100,
"next": "https://api.thrillwiki.com/api/v1/endpoint/?page=2",
"previous": null,
"results": [...]
}
Success Response Format
{
"success": true,
"message": "Operation completed successfully",
"data": {...}
}
❌ Error Response Reference
All error responses follow a consistent format with appropriate HTTP status codes.
Error Logging
All API errors are logged with full context for debugging:
- Request details (method, path, user)
- Error type and message
- Stack trace (for 500 errors)
- Request payload (sanitized)
Logs are sent to Sentry in production for monitoring.
See ADR-007: Logging Standardization for details.
Error Response Structure
{
"error": "Human-readable error message",
"error_code": "MACHINE_READABLE_CODE",
"details": {
"field_name": ["Specific field error message"]
},
"suggestions": ["Suggestion for resolution"]
}
HTTP Status Codes
| Code | Meaning | When Used |
|---|---|---|
| 400 | Bad Request | Invalid request body, missing required fields, validation errors |
| 401 | Unauthorized | Missing or invalid authentication token |
| 403 | Forbidden | Authenticated but lacks permission for the action |
| 404 | Not Found | Requested resource doesn't exist |
| 405 | Method Not Allowed | HTTP method not supported for endpoint |
| 409 | Conflict | Resource conflict (e.g., duplicate entry) |
| 422 | Unprocessable Entity | Request understood but semantically incorrect |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Unexpected server error |
Common Error Codes
Authentication Errors (401)
{
"error": "Authentication credentials were not provided",
"error_code": "AUTHENTICATION_REQUIRED"
}
{
"error": "Token is invalid or expired",
"error_code": "INVALID_TOKEN",
"details": {
"token_type": "access",
"message": "Token has expired"
}
}
Authorization Errors (403)
{
"error": "Permission denied",
"error_code": "FORBIDDEN",
"details": {
"message": "You do not have permission to perform this action.",
"required_permission": "is_staff"
}
}
Validation Errors (400)
{
"error": "Validation failed",
"error_code": "VALIDATION_ERROR",
"details": {
"name": ["This field is required."],
"email": ["Enter a valid email address."],
"password1": [
"This password is too short. It must contain at least 8 characters.",
"This password is too common."
]
}
}
Not Found Errors (404)
{
"error": "Park not found",
"error_code": "NOT_FOUND",
"details": {
"resource": "Park",
"identifier": "nonexistent-park-slug"
}
}
Rate Limit Errors (429)
{
"error": "Request was throttled",
"error_code": "RATE_LIMIT_EXCEEDED",
"detail": "Expected available in 45 seconds.",
"retry_after": 45
}
Conflict Errors (409)
{
"error": "Resource already exists",
"error_code": "DUPLICATE_ENTRY",
"details": {
"field": "username",
"message": "A user with this username already exists."
}
}
📝 Key Data Models
User
| Field | Type | Description |
|---|---|---|
id |
int | Unique identifier |
username |
string | Unique username |
email |
string | Email address |
display_name |
string | Display name |
date_joined |
datetime | Account creation date |
is_active |
boolean | Account active status |
avatar_url |
string | Avatar image URL |
Park
| Field | Type | Description |
|---|---|---|
id |
int | Unique identifier |
name |
string | Park name |
slug |
string | URL-friendly identifier |
description |
string | Park description |
status |
enum | OPERATING, CLOSED_PERM, UNDER_CONSTRUCTION |
park_type |
enum | THEME, AMUSEMENT, WATER, etc. |
opening_year |
int | Year park opened |
location |
object | Location details (city, country, coordinates) |
operator |
object | Operating company |
Ride
| Field | Type | Description |
|---|---|---|
id |
int | Unique identifier |
name |
string | Ride name |
slug |
string | URL-friendly identifier |
category |
enum | RC, DR, FR, WR, TR, OT |
status |
enum | OPERATING, CLOSED_PERM, etc. |
park |
object | Parent park |
manufacturer |
object | Ride manufacturer |
opening_year |
int | Year ride opened |
specifications |
object | Height, speed, length, etc. |
Photo
| Field | Type | Description |
|---|---|---|
id |
int | Unique identifier |
image_url |
string | Full image URL |
caption |
string | Photo caption |
photo_type |
enum | GENERAL, ENTRANCE, RIDE, etc. |
is_primary |
boolean | Primary photo flag |
is_approved |
boolean | Moderation approval status |
uploaded_by |
object | User who uploaded |
created_at |
datetime | Upload timestamp |
📖 Complete curl Examples
Full Authentication Flow
# 1. Register a new account
curl -X POST https://api.thrillwiki.com/api/v1/auth/signup/ \
-H "Content-Type: application/json" \
-d '{
"username": "coasterenthusiast",
"email": "coaster@example.com",
"password1": "MySecurePass123!",
"password2": "MySecurePass123!"
}'
# 2. Login to get tokens
curl -X POST https://api.thrillwiki.com/api/v1/auth/login/ \
-H "Content-Type: application/json" \
-d '{"username": "coasterenthusiast", "password": "MySecurePass123!"}' \
| jq -r '.access' > access_token.txt
# 3. Use the access token for authenticated requests
ACCESS_TOKEN=$(cat access_token.txt)
curl -X GET https://api.thrillwiki.com/api/v1/auth/user/ \
-H "Authorization: Bearer $ACCESS_TOKEN"
# 4. Refresh the token when it expires
curl -X POST https://api.thrillwiki.com/api/v1/auth/token/refresh/ \
-H "Content-Type: application/json" \
-d '{"refresh": "<refresh_token>"}'
# 5. Logout
curl -X POST https://api.thrillwiki.com/api/v1/auth/logout/ \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"refresh": "<refresh_token>"}'
Listing and Filtering Parks
# List all operating parks
curl -X GET "https://api.thrillwiki.com/api/v1/parks/hybrid/?status=OPERATING"
# Search for parks by name
curl -X GET "https://api.thrillwiki.com/api/v1/parks/hybrid/?search=disney"
# Filter by location and rating
curl -X GET "https://api.thrillwiki.com/api/v1/parks/hybrid/?continent=NA&country=US&rating_min=8"
# Paginate through results
curl -X GET "https://api.thrillwiki.com/api/v1/parks/hybrid/?offset=20"
# Get detailed park information
curl -X GET "https://api.thrillwiki.com/api/v1/parks/cedar-point/"
Working with Rides
# List all roller coasters at a specific park
curl -X GET "https://api.thrillwiki.com/api/v1/rides/hybrid/?park=cedar-point&category=RC"
# Filter by speed and height
curl -X GET "https://api.thrillwiki.com/api/v1/rides/hybrid/?speed_min=70&height_min=200"
# Get ride details
curl -X GET "https://api.thrillwiki.com/api/v1/rides/steel-vengeance/"
Uploading Photos
# Upload a park photo
curl -X POST "https://api.thrillwiki.com/api/v1/parks/1/photos/" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "image=@/path/to/photo.jpg" \
-F "caption=Amazing entrance view" \
-F "photo_type=ENTRANCE"
# Upload a ride photo
curl -X POST "https://api.thrillwiki.com/api/v1/rides/42/photos/" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-F "image=@/path/to/coaster.jpg" \
-F "caption=First drop" \
-F "photo_type=GENERAL"
🚨 Important Notes
- Authentication Required: Most write operations require JWT authentication
- Permissions: Admin endpoints require staff/superuser privileges
- Rate Limiting: 60 requests/minute for anonymous, 1000 requests/hour for authenticated users
- File Uploads: Use
multipart/form-datafor photo uploads (max 10MB) - Pagination: Default page size is 20, maximum is 100
- Filtering: Parks and rides support extensive filtering with range parameters
- Cloudflare Images: All media files are served through Cloudflare Images CDN
- Email Verification: New users must verify email before full access
- Token Rotation: Refresh tokens are rotated on each use for security
This documentation covers all available API endpoints in the ThrillWiki v1 API. For detailed request/response schemas, parameter validation, and interactive testing, visit /api/docs/ when the development server is running.