📹 Pornalizer API

v1 — REST JSON ← Back to site
Just want a free tube site, not raw API access? You don't need any of this — head to pornalizer.app, request access, and install the WordPress plugin. It handles everything below for you automatically. This page is for developers building a custom integration.

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.

All responses are JSON. Dates are ISO 8601 UTC. Duration is always in seconds. Slugs are lowercase hyphenated strings used for all filter parameters.

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..."}
Access tokens expire. Store your refresh token securely and use it to obtain fresh access tokens.

Pagination

All list endpoints return paginated results in this format:

{
  "count":    1234,               // total results matching filters
  "next":     "https://...?page=2",
  "previous": null,
  "results":  [ ... ]
}
ParamDefaultMaxDescription
page1Page number
page_size20100Results 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."

StatusMeaning
400Malformed request — check query params against the docs for that endpoint
401Missing or invalid JWT — obtain one via /api/token/
403Valid token, but not permitted for this resource (e.g. embed URL for a video outside your allowed filters)
404Resource doesn't exist — includes videos that were pruned/deactivated since you last saw them

Browse Videos

GET /api/database/browse/ Public

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.

ParamTypeExampleDescription
categoriesstringamateur,milfComma-separated category slugs
tagsstringblonde,outdoorComma-separated tag slugs
performersstringriley-reid,lana-rhoadesComma-separated performer slugs
studiosstringbrazzers,bang-brosComma-separated studio slugs
searchstringhot blonde milfFull-text search (title + description)
sortstringviewsviews · likes · published · trending
page_sizeint50Results 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)

GET /api/database/metadata/ Public

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/<id>/ Public
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:

FieldDescription
performers[].slugTPDB-normalised performer slug (stable across scrapers)
studio.slugTPDB studio slug
tpdb_ratingCommunity rating 0–10
tpdb_background_urlHigh-res background image
tpdb_match_statusmatched | unmatched | skipped
content_typeprofessional (TPDB match) | amateur (unmatched)
Videos that didn't match TPDB still appear in results — they're classified as content_type=amateur and may have performer/tag info from scraper metadata.

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
Performer slugs are stable — they won't change even if a performer's display name is updated. Safe to store in your database as a reference.

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/ Auth required
GET /api/channels/
Authorization: Bearer eyJ...
GET /api/channels/<slug>/videos/ Public (if channel is public)
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/ Auth required
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)

GET /api/changelog/ Auth required

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"}}
    }
  ]
}
Store the changed_at of the last event you processed and use it as ?since= on your next poll. This pattern allows efficient incremental sync with any poll frequency.

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

ParamDefaultDescription
autoplay01 = autoplay on load
muted01 = start muted (required for autoplay)
controls10 = hide player controls
https://pornalizer.app/player/embed/1234/?autoplay=1&muted=1

Secure Embed URL (API Clients)

GET /api/videos/<id>/get-embed/ Auth required

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)

POST /api/track/view/ Auth required

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.