Owner: Engineering Team | Last Updated: 2026-01-30 | Status: Current
This document describes the foundational conventions, authentication mechanisms, and request/response patterns for the WWAI backend API. All feature endpoints (humanizer, detector, documents, payments) follow the conventions described here.
The WWAI API is a RESTful JSON API built on Django REST Framework (DRF). It serves as the backend for the WWAI frontend application and is consumed exclusively by internal clients (the Next.js frontend and server-side middleware).
The API base URL is configured via the NEXT_PUBLIC_BACKEND_URL environment variable in the frontend application.
| Environment | Base URL | Port |
|---|---|---|
| Local Development | http://localhost:3001 |
3001 |
| Staging | Configured per deployment | - |
| Production | Configured per deployment | - |
All endpoints are prefixed with /api/ and organized by domain:
{BASE_URL}/api/user/ # Authentication & user management
{BASE_URL}/api/feature/ # Humanizer, detector, documents
{BASE_URL}/api/payments/ # Pricing, checkout, transactions
{BASE_URL}/api/banner/ # Public banners
All endpoints require a trailing slash (/). This is a Django framework convention enforced at the routing layer. Requests without trailing slashes will receive a 301 Moved Permanently redirect, which can cause issues with POST requests (the body may be dropped on redirect).
# Correct
POST /api/user/login/
# Incorrect - will 301 redirect
POST /api/user/login
Important: Always include the trailing slash in endpoint URLs. Omitting it can result in silent failures where POST bodies are lost during the 301 redirect.
The API uses two authentication mechanisms depending on the caller.
Standard client requests use JWT Bearer tokens in the Authorization header. Tokens are obtained via the login or signup endpoints and refreshed via the token refresh endpoint.
GET /api/user/account/ HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
POST /api/user/refresh/ to obtain new access tokensFor full details, see Authentication Endpoints.
Server-side requests from the Next.js middleware or server components use a shared secret key transmitted via the X-Walter-Internal-Key header. This bypasses JWT authentication for internal service communication.
POST /api/feature/humanizer/ HTTP/1.1
Host: api.example.com
X-Walter-Internal-Key: <internal-secret-key>
Content-Type: application/json
X-Walter-Internal-KeySecurity Note: The internal key must never be exposed to the client. It should only be used in server-side contexts (Next.js API routes, middleware, server components).
| Header | Required | Description |
|---|---|---|
Content-Type |
Yes | Always application/json for JSON payloads; multipart/form-data for file uploads |
Authorization |
Conditional | Bearer <access_token> for authenticated client requests |
X-Walter-Internal-Key |
Conditional | Internal secret key for server-to-server requests |
X-Forwarded-For |
Recommended | Original client IP address (set by proxy/middleware) |
X-Client-IP |
Recommended | Direct client IP address for tracking and rate limiting |
Accept |
Optional | application/json (default) |
The API uses client IP information for rate limiting, abuse detection, and analytics. Two headers are supported:
X-Forwarded-For: 203.0.113.50, 70.41.3.18
X-Client-IP: 203.0.113.50
X-Forwarded-For: Standard proxy header; may contain multiple IPs (leftmost is the original client)X-Client-IP: Direct client IP; preferred when availableThe frontend middleware automatically sets these headers when proxying requests to the backend.
All request bodies must be JSON-encoded (except file uploads which use multipart/form-data).
{
"email": "user@example.com",
"password": "securepassword123"
}
Successful responses return the appropriate HTTP status code with a JSON body. The structure varies by endpoint but follows consistent patterns:
// Single object response
{
"id": 123,
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe"
}
// Paginated list response
{
"count": 150,
"next": "/api/feature/history/?limit=20&offset=20",
"previous": null,
"results": [
{ "id": 1, "title": "Document 1", ... },
{ "id": 2, "title": "Document 2", ... }
]
}
Error responses follow a consistent structure. See Error Codes for comprehensive details.
// Validation error (400)
{
"email": ["This field is required."],
"password": ["This field must be at least 8 characters."]
}
// Authentication error (401)
{
"detail": "Authentication credentials were not provided."
}
// Generic error
{
"detail": "Not found."
}
List endpoints support limit/offset pagination, which is the DRF default pagination style.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 20 | Maximum number of results to return (page size) |
offset |
integer | 0 | Number of results to skip from the beginning |
# First page (items 0-19)
curl -s "${BASE_URL}/api/feature/history/?limit=20&offset=0" \
-H "Authorization: Bearer ${TOKEN}"
# Second page (items 20-39)
curl -s "${BASE_URL}/api/feature/history/?limit=20&offset=20" \
-H "Authorization: Bearer ${TOKEN}"
{
"count": 87,
"next": "https://api.example.com/api/feature/history/?limit=20&offset=40",
"previous": "https://api.example.com/api/feature/history/?limit=20&offset=0",
"results": [...]
}
| Field | Type | Description |
|---|---|---|
count |
integer | Total number of results across all pages |
next |
string | null | Full URL for the next page, or null if on the last page |
previous |
string | null | Full URL for the previous page, or null if on the first page |
results |
array | Array of result objects for the current page |
The API enforces rate limits to protect backend resources and ensure fair usage across all users.
429 Too Many RequestsRetry-After header indicating how many seconds to waitHTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
"detail": "Request was throttled. Expected available in 60 seconds."
}
Request limits are tied to the user's subscription plan:
| Plan | Monthly Requests |
|---|---|
| Free | 500 |
| Trial | 500 |
| Starter | 500 |
| Pro | 1,200 |
| Special | 1,200 |
| Unlimited | 1,700 |
See Payments for full plan details including credit allocations.
The WWAI API currently operates as a single-version API without explicit version numbers in the URL path. All clients consume the same API version.
/api/user/login/, not /api/v1/user/login/)If API versioning becomes necessary, the recommended strategy is URL path versioning:
/api/v1/user/login/
/api/v2/user/login/
| Domain | Method | Endpoint | Auth Required | Description |
|---|---|---|---|---|
| Auth | POST | /api/user/signup/ |
No | User registration |
| POST | /api/user/login/ |
No | Email login | |
| POST | /api/user/login/google/ |
No | Google OAuth login | |
| POST | /api/user/login/facebook/ |
No | Facebook OAuth login | |
| POST | /api/user/refresh/ |
No | Refresh JWT tokens | |
| GET | /api/user/account/ |
Yes | Get user profile | |
| POST | /api/user/forgot-password/ |
No | Request password reset | |
| POST | /api/user/reset-password/ |
No | Reset password with token | |
| Users | POST | /api/user/update-user-email/ |
Yes | Update email address |
| POST | /api/user/add-to-klaviyo/ |
Yes | Add to email marketing | |
| GET | /api/user/billing-portal-redirect/ |
Yes | Stripe billing portal | |
| Features | POST | /api/feature/humanizer/ |
Yes | Humanize text |
| POST | /api/feature/free-humanizer/ |
No | Free tier humanizer | |
| POST | /api/feature/detector/ |
Yes | Detect AI content | |
| POST | /api/feature/ai-detector/ |
Yes | Full AI detection | |
| POST | /api/feature/file-to-html/ |
Yes | Convert file to HTML | |
| Documents | GET | /api/feature/history/ |
Yes | List documents |
| PATCH | /api/feature/history/{id}/ |
Yes | Update document | |
| DELETE | /api/feature/history/{id}/ |
Yes | Delete document | |
| GET | /api/feature/remember-humanizer-selection/ |
Yes | Get saved preferences | |
| POST | /api/feature/remember-humanizer-selection/ |
Yes | Save preferences | |
| Payments | GET | /api/payments/pricing/ |
No | Get pricing info |
| POST | /api/payments/new-chekout/ |
Yes | Create checkout session | |
| GET | /api/payments/transaction/ |
Yes | Get transaction details | |
| Banners | GET | /api/banner/public/ |
No | Get public banners |
The API is configured to accept requests from authorized frontend origins. In development, localhost origins are permitted. In production, only the configured frontend domain is allowed.
| Date | Author | Change |
|---|---|---|
| 2026-01-30 | Admin | Initial creation |
Next: API Reference - Authentication Endpoints | Up: WalterWrites