Overview
The Pornalizer API provides access to a continuously updated video database. Videos are sourced from multiple scrapers and enriched with metadata from TPDB (The Porn Database).
The public browse endpoint requires no authentication — you can start pulling videos immediately. Authentication (JWT) is required for embed URLs, channels, webhooks, and usage stats.
Base URL
https://pornalizer.app/api/
Authentication
Public endpoints work without any credentials. Protected endpoints require a JWT Bearer token.
Getting a token
POST /api/token/
Content-Type: application/json
{
"username": "your_username",
"password": "your_password"
}
Response:
{
"access": "eyJ...", // use this in Authorization header
"refresh": "eyJ..." // use to get a new access token
}
Using the token
GET /api/videos/123/get-embed/
Authorization: Bearer eyJ...
Refreshing
POST /api/token/refresh/
Content-Type: application/json
{"refresh": "eyJ..."}
Pagination
All list endpoints return paginated results in this format:
{
"count": 1234, // total results matching filters
"next": "https://...?page=2",
"previous": null,
"results": [ ... ]
}
| Param | Default | Max | Description |
|---|---|---|---|
| page | 1 | — | Page number |
| page_size | 20 | 100 | Results per page |
Rate Limits & Errors
There's no hard per-minute request cap on API tokens today — build integrations that poll reasonably (the changelog endpoint exists specifically so you don't need to re-poll browse on a tight loop). Sustained abusive traffic can result in throttling or the token being revoked.
/api/database/browse/ and /api/database/metadata/ are cached at the edge for 30 seconds per unique query — identical requests within that window return the cached response, not a fresh query. This is transparent to normal usage but worth knowing if you're debugging a value that "hasn't updated yet."
| Status | Meaning |
|---|---|
| 400 | Malformed request — check query params against the docs for that endpoint |
| 401 | Missing or invalid JWT — obtain one via /api/token/ |
| 403 | Valid token, but not permitted for this resource (e.g. embed URL for a video outside your allowed filters) |
| 404 | Resource doesn't exist — includes videos that were pruned/deactivated since you last saw them |
Browse Videos
The primary endpoint for fetching videos. Supports rich filtering by category, tag, performer, full-text search, and sorting. All filter params accept comma-separated slugs.
| Param | Type | Example | Description |
|---|---|---|---|
| categories | string | amateur,milf | Comma-separated category slugs |
| tags | string | blonde,outdoor | Comma-separated tag slugs |
| performers | string | riley-reid,lana-rhoades | Comma-separated performer slugs |
| studios | string | brazzers,bang-bros | Comma-separated studio slugs |
| search | string | hot blonde milf | Full-text search (title + description) |
| sort | string | views | views · likes · published · trending |
| page_size | int | 50 | Results per page (max 100) |
Example — browse all
GET /api/database/browse/
GET /api/database/browse/?page_size=50&sort=views
Example — filter by category
GET /api/database/browse/?categories=amateur
GET /api/database/browse/?categories=milf,blonde&sort=published
Example — search + filter
GET /api/database/browse/?search=outdoor+pool&categories=amateur&sort=trending
Live example slugs (from your database)
Categories: 757-virginiabeach amateur-1 bwc-1 chubby-1 chubbywifexploding
Tags: 051 052 053 1-hour-plus 1000facials
Performers: 007movie 00hottits1991 076503
Response object
{
"count": 4821,
"next": "https://pornalizer.app/api/database/browse/?page=2",
"previous": null,
"results": [
{
"id": 1234,
"title": "Example Video Title",
"slug": "example-video-title",
"description": "...",
"duration": 1847, // seconds
"published_at": "2024-01-15T00:00:00Z",
"thumbnail_url": "https://...",
"view_count": 9821,
"like_count": 512,
"content_type": "amateur", // amateur | professional
"categories": [
{"id": 1, "name": "Amateur", "slug": "amateur"}
],
"tags": [
{"id": 5, "name": "Blonde", "slug": "blonde"}
],
"performers": [
{"id": 12, "name": "Riley Reid", "slug": "riley-reid",
"thumbnail_url": "https://..."}
],
"studio": {
"id": 3, "name": "Brazzers", "slug": "brazzers"
}
}
]
}
Metadata (All Filters)
Returns all available categories, tags, and performers — use this to populate dropdowns or build search UIs before making browse queries.
GET /api/database/metadata/
{
"categories": [
{"id": 1, "name": "Amateur", "slug": "amateur", "video_count": 1200}
],
"tags": [
{"id": 5, "name": "Blonde", "slug": "blonde"}
],
"performers": [
{"id": 12, "name": "Riley Reid", "slug": "riley-reid",
"thumbnail_url": "https://..."}
]
}
Video Detail
GET /api/videos/1234/
Returns the same fields as the browse response, but for a single video. Does not include the embed URL — use the Secure Embed endpoint for that.
TPDB — The Porn Database
Videos in the database are automatically enriched with metadata from ThePornDB.net (TPDB). This provides standardised performer names, studio names, tags, ratings, and background images.
TPDB-matched videos have additional fields populated:
| Field | Description |
|---|---|
| performers[].slug | TPDB-normalised performer slug (stable across scrapers) |
| studio.slug | TPDB studio slug |
| tpdb_rating | Community rating 0–10 |
| tpdb_background_url | High-res background image |
| tpdb_match_status | matched | unmatched | skipped |
| content_type | professional (TPDB match) | amateur (unmatched) |
Filtering by Performer (TPDB)
Use TPDB-normalised performer slugs (lowercase, hyphenated) in the performers param. Fetch the full list from /api/database/metadata/.
GET /api/database/browse/?performers=riley-reid
GET /api/database/browse/?performers=riley-reid,lana-rhoades&sort=views
GET /api/database/browse/?performers=abella-danger&categories=amateur
Filtering by Studio (TPDB)
Use the studios param with studio slugs from metadata.
GET /api/database/browse/?studios=brazzers
GET /api/database/browse/?studios=bang-bros,reality-kings&sort=published&page_size=50
Channels
Channels are curated video feeds defined by filter rules (categories, tags, performers, studios). Public channels are accessible without authentication.
GET /api/channels/
Authorization: Bearer eyJ...
GET /api/channels/my-milf-channel/videos/
GET /api/channels/my-milf-channel/videos/?page=2&page_size=50
Create a Channel
POST /api/channels/
Authorization: Bearer eyJ...
Content-Type: application/json
{
"name": "My Amateur Channel",
"description": "Amateur content only",
"filter_categories": [1, 3], // category IDs
"filter_tags": [5, 8], // tag IDs
"filter_performers": [], // performer IDs
"filter_studios": [], // studio IDs
"filter_search": "", // optional keyword filter
"min_duration_seconds": 300, // optional: minimum duration (seconds)
"sort_by": "published", // published | views | likes | trending
"is_public": true // make channel publicly accessible
}
The channel will automatically update as new matching videos are added to the database.
Changelog (Incremental Sync)
Use this to keep your database in sync. Each entry is an event: video_added, video_updated, or video_deleted.
GET /api/changelog/?since=2024-01-01T00:00:00Z
Authorization: Bearer eyJ...
{
"count": 47,
"results": [
{
"id": 9901,
"event_type": "video_added",
"video_id": 1234,
"video_title": "New Video Title",
"changed_at": "2024-02-01T14:30:00Z",
"changes": {}
},
{
"id": 9902,
"event_type": "video_updated",
"video_id": 1200,
"video_title": "Updated Video",
"changed_at": "2024-02-01T14:31:00Z",
"changes": {"title": {"from": "Old Title", "to": "New Title"}}
}
]
}
Webhooks
Set your webhook URL in your account profile. Pornalizer will POST to it whenever a video is added or updated. Deliveries are retried with exponential backoff on failure.
Webhook payload
POST https://your-server.com/your-webhook-endpoint
Content-Type: application/json
X-Webhook-Event: video_added
{
"event": "video_added",
"timestamp": "2024-02-01T14:30:00Z",
"video": {
"id": 1234,
"title": "New Video",
"slug": "new-video",
"duration": 1847,
"published_at": "2024-01-15T00:00:00Z",
"thumbnail_url": "https://...",
"categories": [...],
"tags": [...],
"performers": [...],
"studio": {...}
}
}
Check delivery status
GET /api/webhooks/deliveries/?status=failed
Authorization: Bearer eyJ...
Retry a failed delivery
POST /api/webhooks/deliveries/42/retry/
Authorization: Bearer eyJ...
Embed Player
Every video has a public embed player accessible at:
<iframe
src="https://pornalizer.app/player/embed/1234/"
width="100%" height="450"
frameborder="0"
allowfullscreen
allow="autoplay; fullscreen"
></iframe>
Or by slug:
<iframe src="https://pornalizer.app/player/embed/slug/my-video-slug/" ...></iframe>
Player URL parameters
| Param | Default | Description |
|---|---|---|
| autoplay | 0 | 1 = autoplay on load |
| muted | 0 | 1 = start muted (required for autoplay) |
| controls | 1 | 0 = hide player controls |
https://pornalizer.app/player/embed/1234/?autoplay=1&muted=1
Secure Embed URL (API Clients)
Returns a time-limited, signed embed URL for a specific video. Use this if you need to embed videos on your own player without exposing the raw host URL.
GET /api/videos/1234/get-embed/
Authorization: Bearer eyJ...
{
"video_id": 1234,
"embed_url": "https://dood.watch/e/abc123xyz",
"host": "DoodStream",
"expires_at": "2024-02-01T16:00:00Z"
}
View Postback (Analytics)
Report a view event from your own player or site. Useful if you're embedding content and want view counts to reflect real user activity on your platform.
POST /api/track/view/
Authorization: Bearer eyJ...
Content-Type: application/json
{
"video_id": 1234,
"viewer_ip": "1.2.3.4", // optional: your user's IP
"country": "US", // optional: 2-letter country code
"device": "mobile", // optional: mobile|desktop|tablet
"duration_watched": 180, // optional: seconds watched
"referrer": "https://yoursite.com/videos/page"
}
{"recorded": true}
Questions? Contact support or refer to the admin panel for API key management.