Skip to main content

2026-10-13

Added

  • History rows from /me/history, and history and playback rows from /me/sync/snapshot and /me/sync/changes, now include sourceSeason and sourceEpisode: the episode in TMDB numbering. They differ from season and episode only for an anime episode stored in TVDB order, and are null for movies. See Anime episode numbering
  • /playback/in-progress items now document sourceSeason and sourceEpisode, which they already returned

Fixed

  • /playback/in-progress no longer hides an item because the user watched that title before. Only a watch logged at or after the item’s last playback event clears it, so a rewatch stays resumable

2026-10-12

Added

  • History results from POST /api/platform/v1/sync/history now include stored: the media source, source id, season and episode the row was saved under. Anime episodes are kept in TVDB order, so these can differ from the numbers sent. See Anime episode numbering
  • History rows from /me/history, /me/sync/snapshot and /me/sync/changes now include clientItemId, the client_item_id your app sent when it wrote the row, or null for rows written any other way

2026-10-05

Changed

  • Refreshing with the previous refresh token within 60 seconds of exchanging it now returns a new token pair instead of invalid_grant, so a lost refresh response no longer forces the user to reconnect. The pair from the lost response is no longer valid; only the newest pair is
  • Presenting a refresh token pair that such a retry replaced now revokes the connection, as presenting the previous token after the 60 seconds already did
  • Two concurrent refreshes with the same refresh token now both succeed instead of one failing with invalid_grant; only the later pair stays valid

2026-09-29

Added

  • Continue Watching summaries now document fields they already returned: currentSeasonNumber, currentSeasonName, currentSeasonEpisodesWatched, currentSeasonEpisodesTotal, currentSeasonPercent, currentSeasonMinutesRemaining, episodeRuntimeSource, and episodeBackdropUrl
  • Continue Watching summaries now include earlierUnwatchedSourceSeason, earlierUnwatchedSourceEpisode, and earlierUnwatchedEpisodeTitle for linking to the earlier gap
  • Continue Watching summaries now include currentSeasonEpisodesUnaired, the announced episodes of the current season that have not aired yet

Changed

  • earlierUnwatchedSeason and earlierUnwatchedEpisode now point at the earliest gap in a season the user has started before falling back to seasons they never started. earlierUnwatchedCount still counts every aired unwatched episode before the last-watched one
  • currentSeasonMinutesRemaining now sums each remaining episode’s listed runtime instead of multiplying by an average

Fixed

  • GET /api/platform/v1/title/{type}/{id} no longer includes the user’s private per-title note in interaction. The field was never documented; interaction now contains exactly watchedAt, rating, isFavourite, and showStatus

2026-09-22

Added

  • Continue Watching summaries now include earlierUnwatchedSeason, earlierUnwatchedEpisode, and earlierUnwatchedCount, allowing clients to surface aired gaps separately from the forward “next episode” action
  • Continue Watching summaries now include releasePhase, a schedule-based display state separate from the existing provider status

Fixed

  • nextSeason and nextEpisode now advance from the last-watched episode instead of rewinding to an earlier unwatched gap, and continue to exclude unaired episodes
  • Fully caught-up shows remain in Continue Watching when their next episode is announced, even when it does not yet have an air date
  • Continue Watching and recent-history surfaces replace identifier-shaped stored titles such as tmdb:124101 with canonical catalog names when available; show years use the canonical premiere year

Updated

  • nextEpisodeToAir.airDate is explicitly optional so clients can represent announced but unscheduled episodes

2026-09-19

Fixed

  • Setting a show’s showStatus to DROPPED now removes it from Continue Watching, Up Next, and upcoming/calendar recommendations without deleting watch history
  • Site and Platform API drop/undrop actions now update the same state, including canonical TMDB/TVDB aliases; setting another status or null restores the show

Updated

  • Ratings, favourites, and watch-status library endpoints now honor pageSize (capped at 100)
  • Watch-status reads now return all title-level statuses by default and can be filtered explicitly with status=DROPPED

2026-09-05

Documentation updates

  • Corrected quickstart scopes and playback examples.
  • Fixed Kotlin authentication and sync examples.
  • Clarified pagination, rate limits, live events, and playback progress.
  • Updated the OpenAPI reference and SDK installation guidance.

2026-08-09

Fixed

  • An incomplete POST /api/platform/v1/playback/stop now creates inactive Continue Watching progress without requiring a preceding live playback event
  • A later passive resume snapshot can update the same stable playback_session_id instead of being silently deduped after the first stop
  • Resume snapshots are ordered by provider event_created_at rather than database write time, preventing delayed older snapshots from replacing newer progress
  • Unexpected playback processing failures now return the standard error envelope and request ID and are retained in platform request logs
  • Collection creation no longer returns a successful response with a null resource ID after a uniqueness race

Updated

  • Playback payloads now reject unknown fields and invalid ranges. progress is a ratio from 0 to 1 and can derive position_seconds when duration_seconds is supplied
  • Playback failures now distinguish 400 invalid_request, 409 playback_state_conflict, 422 media_not_found, and 500 server_error
  • The Platform API contract is now 1.0.0-beta.4

Breaking

  • Playback writes now require event_id, event_created_at, media_type, title, and playback_session_id. Episode writes also require season and episode
  • A standalone pause now returns 409 playback_state_conflict instead of reporting success without creating visible progress

Clarified

  • Passive resume imports should send one incomplete stop; progress followed by pause is reserved for live playback state

2026-07-29

Security

  • Access tokens now expire after one hour instead of 30 days, for both the OAuth and device-code flows. They’re bearer credentials with no proof of possession and travel widely — addon config files, mobile storage, proxy logs, crash reports — so a short lifetime bounds the exposure window from leaks that go unnoticed. Refresh promptly on 401, or shortly before expires_in elapses
  • Refresh tokens already rotated on use; a consumed one is now recognised as replayed rather than merely invalid. Replaying a refresh token revokes its entire chain, since a legitimate client already exchanged it

Fixed

  • The change feed could permanently skip a change. Ids are assigned when a change is written but only become visible when its transaction commits, so two changes committing out of order could leave one behind an advanced cursor, silently desynchronising a mirror. Cursors now also record which transactions were open when issued, and re-check them on the next read

Updated

  • Change-feed delivery is now explicitly at-least-once. Apply changes idempotently, keyed on resource and resourceId — receiving one twice is normal. Existing cursors keep working and upgrade automatically on their next read

2026-07-28

Added

  • Bulk writes at POST /api/platform/v1/sync/history, /sync/ratings, and /sync/watchlist, accepting up to 100 items and 512 KiB per request
  • A durable change feed at GET /api/platform/v1/me/sync/changes and per-resource backfill at GET /api/platform/v1/me/sync/snapshot, so large clients mirror an account instead of re-polling library endpoints. Cursors stay valid for 90 days
  • Required Idempotency-Key on every bulk write, with results replayed for 24 hours
  • Token revocation at POST /api/platform/v1/oauth/revoke (RFC 7009)
  • OAuth server metadata at /.well-known/oauth-authorization-server (RFC 8414), so standard OAuth libraries can discover the endpoints
  • X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset on every platform response, exposed via CORS for browser clients
  • Cursor pagination on GET /api/platform/v1/me/collection and GET /api/platform/v1/me/lists via limit and cursor, returning nextCursor

Updated

  • Every authenticated endpoint now enforces a per-token bucket (300 reads or 120 writes per minute) and a per-app bucket (6,000 per minute across all its users). Endpoint-specific limits apply on top of these
  • Bulk sync accepts 512 KiB bodies rather than the general 64 KiB ceiling, so a full 100-item batch of long-titled entries is no longer rejected
  • Every 429 now carries Retry-After

Fixed

  • /.well-known/oauth-authorization-server returned an issuer with a trailing slash. RFC 8414 requires it to match the string the well-known URI was built from, and strict OAuth clients abandoned discovery on the mismatch

Breaking

  • GET /api/platform/v1/me/collection and GET /api/platform/v1/me/lists now return a bounded page (100 and 50 by default) plus nextCursor, where they previously returned the entire set. Follow nextCursor to retrieve everything
  • A stale Idempotency-Key whose original request died before recording its result now returns 409 idempotency_indeterminate instead of silently re-running the write. That mutation may already have applied: reconcile through /me/sync/changes and retry with a new key

2026-07-27

Updated

  • Platform errors now consistently return error, message, and request_id, including delegated list, history, rating, collection, and profile failures
  • Platform JSON and form bodies are capped at 64 KiB with a 10-second read timeout; the OpenAPI contract now documents 408 and 413 responses
  • OAuth and device-flow status contracts now match production, including HTTP 400 for authorization_pending, 401 for invalid clients, and explicit 302 authorization redirects
  • List and collection writes now derive anime classification from canonical TVDB identity when clients omit the optional compatibility hint

2026-07-26

Added

  • Stable anime search, trending, and discovery through the public catalog API
  • Explicit anime classification on collection items while preserving their routable movie/show kind

Updated

  • Anime titles use TMDB base identities with TVDB enrichment and official episode ordering for mapped series
  • Playback, list, collection, SDK, and OpenAPI contracts now distinguish anime category from movie/show kind
  • Legacy provider-ID translation remains an internal import and redirect compatibility concern

2026-07-23

Updated

  • All 16 developer-app scopes are now listed consistently across the Authentication guide, native-app guide, and OpenAPI reference
  • PunchPlay’s APNs device-registration routes are enforced as first-party-only; third-party apps retain notification inbox, unread-state, and preference access
  • Authenticated Platform API operations now publish concrete request and success-response schemas instead of generic JSON placeholders
  • Public catalog and community rate limits are documented alongside the existing public-profile limit

2026-07-19

Added

  • Stable public catalog search, trending, and discovery endpoints
  • Stable public community overview and authenticated community-stat endpoints
  • Native notification inbox, unread count, mark-read, and notification-preference endpoints
  • First-party-only APNs push-device registration and removal endpoints
  • Native trophy, profile, and user-preference endpoints
  • Four least-privilege scopes: notifications:read, notifications:write, trophies:read, and profile:write

Updated

  • Native clients can keep discovery, community, notifications, trophies, profile editing, and preferences inside the app
  • Sensitive account operations such as password, email, imports, connected services, and account deletion remain web-only
  • The recommended first-party mobile authorization set now contains 16 scopes

Notes

  • Anime discovery was not yet included in that mobile-client release
  • Third-party apps can use the notification inbox and preference APIs, but PunchPlay’s APNs device-registration routes are reserved for first-party clients

2026-07-18

Added

  • Platform title, season, and episode detail endpoints for native clients
  • Watch-history reads, logging, date editing, and deletion
  • Ratings, favourites, planning, and watch-status reads and writes
  • User list CRUD and list-item management
  • Physical and digital collection reads and writes
  • Calendar and Continue Watching endpoints
  • Public documentation for all 12 developer-app scopes

Updated

  • Native clients can now implement the core PunchPlay movie and TV experience without linking to the web application
  • The OpenAPI reference now covers the complete /api/platform/v1 route tree
  • OAuth guidance now recommends authorization code + PKCE for native apps that can receive a callback
  • The reserved email:read scope is no longer offered to developer apps

Current boundary

  • Notifications, trophies, and account settings remain web experiences
  • Community endpoints are used by the first-party mobile client but are not yet part of the stable /api/platform/v1 contract
  • Anime discovery was not yet included in that mobile-client release

2026-06-16

Added

  • Persistent platform request logging keyed by request_id for support and incident investigation
  • Open developer app registration in PunchPlay settings for confidential and public clients

Updated

  • OAuth refresh responses now rotate and return a new refresh_token with refresh_expires_in
  • Device refresh responses now rotate and return a new refresh_token with refresh_expires_in
  • Playback and auth docs now document the current debugging and token rotation contract
  • OpenAPI reference now reflects the live refresh-token response shape

2026-06-09

Added

  • Authorization code + PKCE support for PunchPlay developer apps
  • App-level allowed_scopes policy for developer app registration
  • Request-scoped platform error IDs via request_id and X-PunchPlay-Request-Id
  • Scope enforcement updates across /me, playback, device auth, and OAuth token flows
  • Connected app revocation support in user settings

Updated

  • Authentication docs now cover both OAuth and device code flows
  • Quickstart now reflects web, browser, native, desktop, and TV integration paths
  • Error docs now describe the current debugging and support contract
  • OpenAPI reference now reflects the current platform auth surface

2026-06-08

Added

  • Initial PunchPlay developer portal
  • Platform API documentation for device authentication
  • Platform playback documentation for start, pause, resume, stop, and progress
  • Live playback guides for now-playing, in-progress, and SSE updates
  • Public API documentation for public user profile data
  • Generated endpoint reference from the initial OpenAPI definition
  • Developer app registration with client_id issuance
  • Confidential and public client support
  • Scope-aware platform tokens

Notes

  • The current public platform contract is v1.
  • Future work is expected in areas such as app registration automation, outbound webhooks, and richer read and write surfaces.