- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols. - Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage. - Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
41 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 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.