EasyPlexVersion 2.4 handbook Professional servicesServices

Operator documentation · 2.4

From clean server to
ready to stream.

The current guide for deploying the Laravel control panel, connecting the native Android app, securing the mobile API, and operating EasyPlex 2.4.

Release-ready workflow
  1. 01
    Deploy the panelLaravel 9 · PHP 8 · MySQL
  2. 02
    Activate and configureAdmin-managed runtime settings
  3. 03
    Pair the Android appSigned requests · encrypted responses
  4. 04
    Test and releaseAndroid API 36 · minSdk 24

Release notes

What changed in 2.4

This release is more than a visual update. Database, API security, playback, monetization, and admin workflows changed together.

01

Safer upgrades

An idempotent 2.3→2.4 upgrader supports dry runs, skips existing schema, and validates the result.

02

Mobile API hardening

HMAC request signatures, nonce replay prevention, session binding, optional response encryption, certificate pins, and Play Integrity.

03

Verified payments

Stripe, PayPal, and admin-approved offline payments remain supported. RevenueCat and its public webhook have been removed.

04

Credits & unlocks

Credit packages, transaction history, per-content prices, permanent or every-play unlock policies, and ad unlocks.

05

Richer experience

Profiles, profile-scoped watch history, reels and reactions, request management, PiP, auto-play next, RTL, offline states, Chromecast UI, and configurable episode cards.

06

Centralized control

Branding, home-rail order, app updates, SMTP, runtime values, FFmpeg, storage, VPN, country rules, API limits, and mobile secrets live in the admin settings workspace.

System map

How the pieces connect

Android sourceAndroid Source/EasyPlex2.4/
Laravel sourceWebPanel2.4/development/WebPanel2.4-development.zip
API base formathttps://your-domain.example/api/

Before you begin

Requirements

AreaRequiredProduction notes
BackendPHP 8.0.2+, Composer 2, MySQL/MariaDB, HTTPSLaravel 9.52. Enable OpenSSL, PDO MySQL, cURL, Mbstring, JSON, Fileinfo, XML, GD/Imagick, ZIP and Sodium where available.
Web serverApache with mod_rewrite or NginxPoint the document root to Laravel’s public/ directory and deny direct access to .env, vendor/, and storage/.
Server capacity2 vCPU, 2 GB RAM, 5 GB free diskThis is a practical minimum for a small catalog without local video processing. Use 4 GB+ RAM and storage sized for artwork, backups, uploads, logs, and FFmpeg temporary/output files in production.
RuntimeCron access and writable storageRedis is strongly recommended for production cache and atomic nonce replay protection. Configure a continuously supervised queue worker for background jobs.
Vue build toolsNode.js 20.x and npm 10.xRequired only when editing and rebuilding the Vue admin assets. Run npm ci, then npm run prod. Buyers who use the supplied compiled assets do not need Node.js at runtime.
AndroidCurrent Android Studio with JDK 17, Android SDK 36The project targets API 36, has minimum API 24, uses Gradle 9.4.1 and Android Gradle Plugin 9.2.1. App source compatibility remains Java 11.
AccountsTMDB keyFirebase/OneSignal, payment, ad network, AWS/Wasabi/Cloudflare R2, and social OAuth accounts are only needed for the features you enable.

Accounts · pricing · terms

Third-party services are not included

EasyPlex supplies integration code, not third-party accounts, credentials, quotas, subscriptions, or usage fees. Configure only the services you need and check their current terms before launch.

ServiceWhat the buyer must provideCosts, limits, and terms
StripeMerchant account plus API and webhook credentialsProcessing, dispute, conversion, and other fees may apply. Country eligibility and Stripe terms apply.
PayPalBusiness/developer account plus API and webhook credentialsTransaction, withdrawal, conversion, dispute, and other fees may apply. PayPal terms apply.
Firebase / FCMGoogle/Firebase project and buyer-supplied app or service configurationFree quotas and product limits apply; some Google Cloud usage may require billing. Google terms apply.
OneSignalOneSignal account, application, and credentialsPlan limits, message allowances, and paid features vary. OneSignal terms apply.
TMDB APITMDB account and API key; commercial use may require a separate written agreement with TMDBAttribution, rate limits, branding, API usage, content terms, and any applicable commercial fees apply. EasyPlex is not endorsed by TMDB.
S3-compatible storageAWS or compatible provider account, bucket, endpoint, and credentialsStorage, request, transfer/egress, CDN, and infrastructure charges may apply under the selected provider's terms.
Cloudflare R2Cloudflare account, R2 bucket, scoped S3 API credentials, account endpoint, and public delivery URLStorage, operations, retrieval, custom-domain, quota, and service terms apply. The r2.dev URL is intended for development; use a custom domain for production delivery.
GeoIP providerProvider account or licensed database and, where required, an API keyLookup quotas, fees, privacy, retention, and regional-compliance rules depend on the selected provider.
Google Sign-InGoogle Cloud/Firebase project, OAuth clients, consent screen, and signing fingerprintsQuotas, verification, branding, data-use, and Google platform terms apply. Connected Google services may have separate billing.
Facebook LoginMeta developer account and Facebook app, credentials, configuration, and any required reviewMeta platform, privacy, branding, data-use, and regional-availability terms apply; connected services may impose separate limits or costs.
Advertising networksSeparate publisher accounts, app/placement IDs, consent setup, and policy complianceEligibility, revenue, quotas, SDK terms, and possible costs vary by network.
DRM / license serverLicensed media plus any required DRM vendor agreement and license-server serviceDRM licensing, hosting, and media-delivery charges are not included.
Email / SMTPBuyer-supplied SMTP or mail-provider account and credentialsSending limits, domain verification, anti-spam rules, and usage charges depend on the provider.

Server · new installation

Install the Laravel panel

Run commands from the backend project root. On shared hosting, use the host’s terminal or run the equivalent deployment steps locally before upload.

  1. Upload and expose only public/

    Deploy the backend files. Configure the domain document root as /path/to/LaravelEasyplex/public. If your host cannot change it, move only the contents of public/ to the web root and carefully update paths in index.php.

  2. Create the environment file

    Copy .env.example to .env. Set APP_ENV=production, APP_DEBUG=false, the HTTPS APP_URL, and database credentials. Keep .env outside public access.

    .env — essential values
    APP_NAME=EasyPlex
    APP_ENV=production
    APP_KEY=
    APP_DEBUG=false
    APP_URL=https://stream.example.com
    
    DB_CONNECTION=mysql
    DB_HOST=127.0.0.1
    DB_PORT=3306
    DB_DATABASE=easyplex
    DB_USERNAME=easyplex_user
    DB_PASSWORD=use-a-strong-password
    
    CACHE_DRIVER=file
    SESSION_DRIVER=file
    QUEUE_CONNECTION=database
  3. Install and initialize

    The release intentionally does not bundle Composer’s vendor/ directory. Install the locked production dependencies on the server after upload:

    Terminal
    composer install --no-dev --optimize-autoloader
    php artisan key:generate
    php artisan migrate --force
    php artisan db:seed --force
    php artisan passport:keys
    php artisan storage:link
    php artisan optimize:clear

    The bundled seed creates temporary administrator and user accounts. Their first-login credentials and mandatory security steps are shown in the clearly labeled Default credentials after seeding section immediately below.

  4. Set permissions

    The web-server user must be able to write to storage/ and bootstrap/cache/. Uploaded artwork and generated files also depend on the configured public storage disk.

  5. Configure background work

    Cron (every minute)
    * * * * * cd /path/to/LaravelEasyplex && php artisan schedule:run >> /dev/null 2>&1

    Also keep a supervised php artisan queue:work --tries=3 process running when using database/Redis queues. Copy the complete production configuration from the dedicated Supervisor and systemd queue-worker guide.

  6. Activate EasyPlex

    Open your domain. On the Activate Easyplex screen, confirm that the detected domain is correct, enter your own purchase code, and select Activate License. The red “Activation not found” notice is expected before a new domain has been activated.

    EasyPlex panel authorization screen with the domain, purchase-code field, and Activate License button
    Panel authorization. Use your production domain and purchase code—the values visible in this example are illustrative only. Select the image to enlarge it.
  7. Synchronize the verified panel files

    After activation, EasyPlex may show the Pre-Installation Update page. When the status says an update is available and the download is authorized, select Sync panel files. Keep the page open until synchronization finishes; do not refresh the browser or interrupt PHP during this operation.

    EasyPlex Pre-Installation Update screen showing an available authorized package and the Sync panel files button
    Pre-installation update. Select “Sync panel files” to align the installed admin interface with the latest verified release.
  8. Secure the administrator and configure the panel

    When the dashboard opens, sign in to the administrator account, immediately replace the seeded password, and then work through the settings checklist below.

First login · seeded database

Default credentials after seeding

These accounts are created by php artisan db:seed --force and are also present in the supplied EasyPlex 2.4 SQL database. Open https://your-domain.example/login after installation and license activation.

AccountEmailTemporary passwordPurpose
Administrator[email protected]ChangeMe!EasyPlex24Initial administration-panel login.
Sample mobile user[email protected]ChangeMe!EasyPlexUser24Temporary application testing account.
  1. Visit /login and sign in with the administrator row above.
  2. Open the administrator profile/account controls and replace the email and password.
  3. Open Users, then delete the sample user or assign it unique credentials.
  4. Sign out, verify the old administrator password no longer works, then sign in with the new credentials.
  5. Store the new administrator password in a password manager and enable the server protections described in this guide.

Server · existing installation

Upgrade 2.3 to 2.4

Upgrade the existing 2.3 database through phpMyAdmin by importing the SQL file included in the update package.

BackupDeploy 2.4phpMyAdminSelect databaseImport SQLVerify
  1. Back up the 2.3 installation

    In phpMyAdmin, select the current EasyPlex database, open Export, choose the SQL format, and download a complete backup. Also copy .env, storage/app/public/, uploaded media, OAuth keys, and any customized files. Do not continue until the backup has finished downloading.

  2. Deploy the 2.4 panel files

    Put the website in maintenance mode if available, then upload the 2.4 web-panel files. Preserve the production .env file and uploaded storage—do not replace them with package defaults.

  3. Open the correct database in phpMyAdmin

    Sign in to phpMyAdmin and select the database used by the existing EasyPlex 2.3 installation from the left sidebar. If you are unsure which one to select, open the panel’s .env file and use the value of DB_DATABASE.

  4. Choose the included upgrade file

    With the correct database selected, open the Import tab, select Choose file, and browse to this file in the EasyPlex 2.4 package:

    Upgrade_from_2.3_to_2.4easyplex_2_3_to_2_4.sqlSQL database upgrade file

    Keep the format set to SQL. Leave the character set as UTF-8 unless your existing database uses a different known encoding.

  5. Import the SQL file

    Scroll to the bottom of the Import page and select Import or Go. Wait for phpMyAdmin to display a successful import message. Do not close the tab, refresh the page, or import the file a second time while the first request is running.

  6. Clear caches and verify 2.4

    After a successful SQL import, clear the Laravel cache from the hosting terminal or the panel’s Laravel maintenance tools. If terminal access is available, run:

    Terminal
    php artisan runtime:refresh-state
    php artisan optimize:clear
    php artisan queue:restart

    Open the dashboard and verify that settings save correctly. Test authentication, home content, playback, uploads, subscriptions, credits, and scheduled tasks before reopening the application to users.

Control panel

Configure the settings workspace

Version 2.4 moves many values that were formerly edited in .env into database-backed admin settings. Save each tab before leaving it; uploads and utility buttons may execute immediately.

Platform

General · Laravel · Runtime · Security

Brand assets, policy copy, backups, cache tools, mail driver context, locale, logging, GeoIP, JWT, country rules, device protection, VPN and mobile API hardening.

Integrations

Notifications · TMDB · Social Login · Emails

Firebase or OneSignal credentials, metadata language sources, Google/Facebook OAuth, SMTP transport, sender identity and email templates.

Experience

Ads · Player · App · Layout · Content · Updates

Ad networks, playback and subtitles, downloads, RTL, episode card style, drag-and-drop home sections, release notes and forced/optional app updates.

Commerce & media

FFmpeg · Credits · Payments · AWS · Laravel options

Binary diagnostics, video quality profiles, unlock policies, gateways, offline instructions, storage disks and framework/provider values.

Storage · EasyPlex 2.4.20

Configure Cloudflare R2

EasyPlex can use one Cloudflare R2 bucket as the primary destination for panel-managed images, normal movie/series/anime video uploads, and enhanced FFmpeg output. Laravel writes through R2's S3-compatible API; the Android app receives public HTTPS object URLs and never receives the R2 secret key.

  1. Create the R2 bucket

    In Cloudflare Dashboard, open R2 object storage, create a bucket, and choose a permanent name such as easyplex-media. Copy the name exactly; it becomes the panel's R2 bucket value.

  2. Create scoped S3 credentials

    Open Manage R2 API Tokens and create credentials with Object Read & Write access restricted to this bucket. Save the generated Access Key ID and Secret Access Key immediately. Do not use a global Cloudflare API key or place these credentials in Android, JavaScript, source control, or documentation.

  3. Copy the account endpoint

    Copy the S3 API endpoint shown by Cloudflare. EasyPlex expects this format:

    R2 S3 endpoint
    https://<ACCOUNT_ID>.r2.cloudflarestorage.com

    Do not use the public custom domain here and do not append the bucket name.

  4. Configure public delivery

    Open the bucket's Settings page and connect a custom domain such as media.example.com. Use https://media.example.com as the panel's R2 public URL. Cloudflare's r2.dev public development URL can be used for testing, but it is rate-limited and is not recommended for production delivery.

  5. Enter the values in EasyPlex

    Open Admin → Settings → Storage, enable Cloudflare R2 Storage, and complete every R2 field. Selecting R2 disables AWS S3 and Wasabi because only one primary cloud provider can be active.

    EasyPlex fieldCloudflare valueExample
    R2 access key IDAccess Key ID from the scoped R2 API tokenyour-access-key-id
    R2 secret access keySecret Access Key shown once when the token is createdkeep-this-private
    R2 bucketExact bucket nameeasyplex-media
    R2 S3 endpointAccount-level S3 API endpointhttps://ACCOUNT_ID.r2.cloudflarestorage.com
    R2 public URLPublic custom domain or development r2.dev URLhttps://media.example.com
  6. Save, clear caches, and restart workers

    Select Save Settings, then run:

    Laravel maintenance
    php artisan optimize:clear
    php artisan queue:restart

    Queue workers must have outbound HTTPS access to the R2 endpoint. Enhanced video conversion also requires the normal EasyPlex FFmpeg worker configuration.

  7. Verify every upload path

    Upload one artwork image, one normal video file, and one enhanced video. Confirm the saved URLs begin with the configured R2 public URL, play over HTTPS, and appear under EasyPlex-managed prefixes such as images/, movies/, series/, or animes/. Delete a test managed video link and confirm its object is removed. Buyer-supplied external URLs are intentionally never deleted.

ProblemLikely causeFix
403 Forbidden or PutObject deniedWrong bucket, endpoint, token scope, Access Key ID, or secretUse the account-level endpoint, exact bucket name, and a bucket-scoped Object Read & Write token. Rotate exposed credentials.
cURL error 60The server cannot validate Cloudflare's TLS certificate chainUpdate the operating-system/PHP CA bundle or place a current cacert.pem in the Laravel project root. Never disable TLS verification.
Saved URL still uses the panel domainOld compiled config/backend files, missing R2 migration, or stale workersInstall the complete signed EasyPlex 2.4.20 panel update, run migrations, clear caches, and restart queue workers.
Enhanced upload stays near 55%The FFmpeg queue worker is stopped, listening to the wrong queue, or cannot reach R2Check Supervisor/systemd, the configured queue name, failed jobs, and storage/logs/laravel.log. Follow the queue-worker guide.
Browser playback reports CORS errorsThe public R2 hostname does not allow the website originAdd a bucket CORS policy for the exact HTTPS website origin and required GET/HEAD methods, then purge cached responses. Server-side panel uploads and native Android requests do not require browser CORS.

Cloudflare R2 S3 setup guide · R2 API token guide · Public bucket and custom-domain guide · R2 CORS guide

Control panel · visual tour

Know where daily work happens

The left navigation opens the catalog and settings workspaces. These screens are browser-based; routine content and layout changes do not require Android Studio or a terminal. The complete movie and series walkthrough immediately below follows the same current 2.4 forms shown here.

Current EasyPlex 2.4 administration dashboard with content statistics and navigation
Current dashboard. Review catalog totals, active-content ratios, users, installs, updates, and recent activity from the administration landing page.
Current EasyPlex 2.4 Movies management table and Add Movie action
Current Movies workspace. Search, filter, edit, publish, or remove catalog entries and open the add-content workflow.
Current EasyPlex 2.4 Add Movie form
Current Add Movie form. Import or enter metadata, attach licensed media, configure access, and publish from the browser.
Current EasyPlex 2.4 Add Series form
Current Add Series form. Create the parent series before adding its seasons, episodes, streams, and subtitle tracks.
Current EasyPlex 2.4 Animes management table and Add Anime action
Current Animes workspace. Search, filter, bulk-import, update, edit, publish, or remove anime catalog entries from the browser.
Current EasyPlex 2.4 Add Anime form
Current Add Anime form. Import or enter anime metadata, artwork, access rules, seasons, episodes, streams, and subtitles without editing the Android project.
Current EasyPlex 2.4 Application Settings workspace
Current Settings workspace. Configure branding, integrations, playback, security, payments, storage, and mobile behavior by tab.

Catalog · complete no-code workflow

Add a movie or series from the browser

This entire workflow is completed inside the EasyPlex administration panel. You do not edit Android source, open Android Studio, run Composer/npm, or use a terminal. After you save and activate content, the supplied Android app reads it through the existing API automatically.

01PrepareBrowser settings and licensed assets
02CreateMovie or parent series metadata
03AttachStreams, subtitles, downloads
04PublishActivate, place, and test
Movie path

Publish one movie

Use this path when one catalog record points directly to one or more playable movie sources.

DashboardMoviesAdd Movie
  1. Open the creation form

    Sign in as an administrator, select Movies in the left menu, then select Add Movie. The page title must read “Add Movie”.

  2. Find or identify the title

    Use Search Movie by Name, or enter an IMDb identifier such as tt7286456 and select Search. Choose the correct result. If you are entering everything manually, continue to the fields below.

  3. Review identity and artwork

    Confirm Movie Title, Original Title, optional subtitle, external IMDb ID, poster, mobile backdrop, and Android TV backdrop. A URL can be used where supported, or select a local image and press its adjacent Upload button.

  4. Complete discovery metadata

    Select genres, languages, networks/collections when applicable, certification, cast, trailer, details/overview, release date, vote average, popularity, and runtime. Imported data is a starting point—review it before publishing.

  5. Choose access and behavior

    Set Premium Only, Pinned, Push Notification, Enable Download, Enable Ads Unlock, and Enable Stream intentionally. Configure skip-recap timing only when the video contains a recap and the value is expressed in seconds.

  6. Add at least one playable source

    In Video Management → Manual Links, select the server, quality, language, optional header/user agent, and paste the licensed media URL. Mark HLS only for an HLS playlist; enable DRM only with the provider’s UUID and license URI. Set Premium/Active, then select Add Video Link. Alternatively use the panel’s upload or generated-video tabs.

  7. Add optional downloads and subtitles

    Add a download URL only when offline delivery is permitted. In Subtitle Management, provide the subtitle path or upload, choose the correct language and type, then select Add Subtitle. Repeat for each track.

  8. Save and verify

    Select the final Save button. Return to the Movies table, confirm the record is active, open its public details page, and test playback with the same account type—free, premium, or credits—that buyers will use.

Series path

Publish a series with episodes

A series is a hierarchy. Save the parent first, then manage seasons and episodes before testing playback.

DashboardSeriesAdd Series
  1. Create the parent series

    Select Series in the left menu, then Add Series. Confirm the page title reads “Add Series”. Search by series name or enter its IMDb ID and select Search; manual entry is also supported.

  2. Review the parent metadata

    Confirm Series Name, external IMDb ID, original name, subtitle, poster, mobile/TV backdrops, genres, languages, networks, certification, cast, trailer, details, first-air/release date, rating, and other imported values.

  3. Set parent visibility

    Choose Premium Only, Active, Pinned, and Push Notification deliberately. The “Has new episodes” state is auto-detected from TMDB and local season/episode data; do not use it as a substitute for adding episodes.

  4. Save, then reopen the series

    Select Save, return to the Series table, and open Edit for the new record. The saved parent now exposes the complete Seasons & Episodes workspace.

  5. Add or import a season

    In Seasons & Episodes, enter the season number and import it from TMDB, or create it manually with its number, name, overview, air date, and artwork. Save the season and select it in the season rail.

  6. Create and review episodes

    Import the selected season’s episodes or add them manually. For each episode confirm its episode number, title/name, overview, air date, runtime, still image, rating, and access/active settings. Episode numbers must be unique within that season.

  7. Attach episode playback

    Select an episode, open Episode Video Management, and add its server, quality, language, optional header/user agent, URL or upload, HLS/DRM flags, premium state, and active state. Select Add Video Link. Repeat for every episode that should play.

  8. Add episode extras

    Where licensed, add download links and subtitle tracks to the selected episode, using the correct language and subtitle type. Confirm that each attachment belongs to the episode currently selected—not only to the parent series.

  9. Publish the hierarchy

    Save episode changes, then save the series. Confirm the parent series, intended seasons, episodes, and at least one video source per published episode are active.

  10. Test the full sequence

    Open the series in the Android app and verify season switching, episode order, playback, subtitles, premium/credit access, progress, and next-episode behavior. Correct panel data and refresh the app; no Android rebuild is required.

Required to identify

Metadata

  • Title/name and external ID
  • Poster and backdrop
  • Overview, date, runtime
  • Genre and language
Required to play

Media source

  • Server and licensed URL/upload
  • Correct HLS/DRM flags
  • Quality and language
  • Source marked active
Required to appear

Publication

  • Parent record active
  • Episode active for series
  • Access mode matches test user
  • Home rail enabled if desired
Optional enhancements

Experience

  • Trailer and cast
  • Subtitles and downloads
  • Pinning and notifications
  • Credits or ads unlock
Current Add Movie workflow in EasyPlex 2.4
Movie entry point. The current Movies → Add Movie page begins with title or IMDb search, followed by identity, access, artwork, metadata, video, download, and subtitle sections.
Current Add Series workflow in EasyPlex 2.4
Series entry point. The current Series → Add Series page creates the parent record. Save it, reopen Edit, then complete Seasons & Episodes for playable content.
Before leaving the panel

Final browser-only check

  • Visible: parent content and intended episode are active.
  • Playable: at least one compatible, active source opens over HTTPS.
  • Accessible: premium, credits, ads-unlock, and download rules match the test account.
  • Discoverable: metadata, artwork, language, genre, and optional home placement are correct.

Branding · visual checklist

Set the logo, colors, and home layout

Current EasyPlex 2.4 Application Settings screen used for branding
Admin → Settings → General/App. Upload the panel/app logo, compact logo, notification icon, splash artwork, and other exposed brand assets; save the tab and verify their generated URLs.
EasyPlex mobile home and featured content screens
Home presentation. Open Content Control, drag rails into order, disable unused rails, set limits, save, and restart the app to review the result.
EasyPlex settings and downloads screens showing the app visual theme
Theme colors. Set the primary/accent colors in Android app/src/main/res/values/colors.xml, replace launcher/splash assets with Android Studio’s asset tools, rebuild, and check contrast in light/dark and RTL layouts.

Android · current 2.4 interface

Main application screens

These screenshots come from the current EasyPlex 2.4 Android build. They show the latest home, discovery, search, profile, credit, notification, request, RTL, and AndroidX Media3 playback interfaces. Visible rails and actions still depend on the settings enabled in the administration panel.

Current EasyPlex 2.4 Android home screen with featured content and discovery rails
Home and discovery. Featured content, navigation, and administrator-ordered catalog rails.
Current EasyPlex AndroidX Media3 landscape player controls
AndroidX Media3 player. Current landscape playback controls, timeline, actions, subtitles, quality, PiP, and casting surfaces.
Current EasyPlex catalog filter dialog
Catalog filters. Refine discovery using the current filter sheet and supported catalog options.
Current EasyPlex Android search suggestions interface
Search suggestions. Recent and suggested queries help users reach content quickly.
Current EasyPlex next episode player overlay
Next media overlay. Continue, minimize, or completely close the upcoming episode prompt during playback.
Current EasyPlex Android search results screen
Search results. Current results layout for matching movies, series, anime, and other enabled content.
Current EasyPlex profile account and credits screen
Account and credits. Profile details, plan state, credit balance, and account actions in one surface.
Current EasyPlex Android right-to-left browsing and year filter interface
RTL browsing. Mirrored navigation and filtering for supported right-to-left languages.
Current EasyPlex home screen with active user profile
Profile-aware home. The home feed reflects the selected profile and its available content.
Current EasyPlex in-app notifications screen
Notifications. Current in-app inbox for administrator and platform messages.
Current EasyPlex credit unlock interface
Credit unlock. Clear pricing and balance information before a user unlocks protected content.
Current EasyPlex user content requests screen
Content requests. Users can submit and review supported movie or series requests.
Current EasyPlex AndroidX Media3 seek preview player interface
Seek preview. The current Media3 timeline provides a visual preview while navigating playback.

Android · project

Open and brand the app

  1. Open the project root

    In Android Studio choose Open and select the folder containing settings.gradle—not the nested app/ folder. Let Gradle sync finish before changing identifiers.

  2. Set the application ID

    Change namespace and applicationId in app/build.gradle, then refactor the Java package currently under com.easyplexdemoapp. Update the package in Firebase, OAuth, Facebook, deep-link and store configurations at the same time.

  3. Set version and name

    Update versionCode for every store release and set the public versionName. Change the app label in app/src/main/res/values/strings.xml, then replace launcher icons through Android Studio’s Image Asset tool.

  4. Use the correct JDK and SDK

    Set the Gradle runtime to JDK 17, install Android SDK Platform 36 and current Build Tools, then sync. The source compiles with Java 11 compatibility, and the app supports Android 7.0 (API 24) and newer.

Android · configuration

Pair the app with the panel

The backend Security tab generates the matching values. Copy its “Mobile gradle.properties lines” into the Android project’s root gradle.properties.

gradle.properties
SERVER_BASE_URL=https://stream.example.com/api/
APP_ACCESS_PASSWORD_SHA256=
MOBILE_APP_ID=easyplex-mobile
MOBILE_APP_HMAC_SECRET=generated-long-secret
MOBILE_RESPONSE_ENCRYPTION_SECRET=separate-generated-secret
MOBILE_CERTIFICATE_PINS=sha256/BASE64_PIN
MOBILE_SIGNED_REQUESTS_ENABLED=true
MOBILE_PLAY_INTEGRITY_ENABLED=false
MOBILE_API_KEY=copy-from-admin-api-settings
PURCHASE_KEY=your-envato-purchase-code
APPLOVIN_SDK_KEY=
FACEBOOK_CLIENT_TOKEN=
PropertyPurposeImportant rule
SERVER_BASE_URLRetrofit/API and hosted asset baseProduction HTTPS; include /api/ and trailing slash.
MOBILE_APP_IDIdentifies the clientMust exactly match the backend value.
MOBILE_APP_HMAC_SECRETSigns method, path, timestamp, nonce and body hashGenerate in the panel; never commit real values.
MOBILE_RESPONSE_ENCRYPTION_SECRETDerives per-request AES-256-GCM response keysUse a different secret from HMAC.
MOBILE_CERTIFICATE_PINSPins production HTTPS certificatesKeep a backup pin before certificate rotation.
MOBILE_API_KEYRequired bootstrap credential for every backend {code} routeCopy the API key from your panel into uncommitted local.properties, a private Gradle property, or the build environment. It must match the panel value; never edit or commit Constants.java.
PURCHASE_KEYRequired mobile license bindingUse the same Envato purchase code activated in the web panel. Empty release builds are rejected, and the app will stop at startup if the value is empty or does not match the panel. Keep it in uncommitted local.properties or the private build environment.

Android · services

Firebase and push notifications

EasyPlex supports direct Firebase delivery or OneSignal backed by Firebase Cloud Messaging. Configure only one provider as the panel default, but keep the Android Firebase project and google-services.json aligned with the final package name in either case.

Direct Firebase

  1. Create or open a Firebase project and add an Android app using the final application ID.
  2. Download google-services.json and place it in app/google-services.json.
  3. Add SHA-1 and SHA-256 fingerprints for debug and release signing when using Google login, App Links, or Play Integrity.
  4. Choose Firebase in the panel’s notification settings and upload the required server service-account JSON.

OneSignal through FCM

  1. Connect the same Firebase project to a OneSignal Android app using FCM HTTP v1 credentials.
  2. Copy the OneSignal App ID and create an app-level API key.
  3. Choose OneSignal in Admin → Settings → Notifications, then save the App ID, server-only API key, and exact audience segment.
  4. Install the release build on a real device, grant notification permission, and verify its subscription before sending from Admin → Notifications.

Open the complete OneSignal setup guide →

Signing fingerprints
# Debug key (Windows)
keytool -list -v -alias androiddebugkey -keystore "%USERPROFILE%\.android\debug.keystore" -storepass android -keypass android

# Release key
keytool -list -v -alias YOUR_ALIAS -keystore YOUR_RELEASE_KEYSTORE.jks

Android · release

Build a production release

Windows terminal
gradlew.bat clean test
gradlew.bat lintRelease
gradlew.bat bundleRelease
# Or create an APK:
gradlew.bat assembleRelease
  • Use a private release keystore and keep encrypted backups of it and its credentials.
  • Set a unique applicationId, increment versionCode, and align the panel’s Updates version with the APK/AAB.
  • Verify HTTPS, app links, login, playback, downloads, casting, notifications, payments, profiles and the in-app update flow on a release build.
  • Release builds disable cleartext HTTP and enable code/resource shrinking.
  • If required for a target device/store workflow, set ENABLE_16KB_APK_WORKAROUND=true; the build contains an opt-in 16 KB APK alignment verification flow.

Catalog

Content, servers, and playback

AAR resolver · URL reference

Recognized supported-host URL families

Use a complete HTTPS watch, embed, or share URL in the format shown. Replace every uppercase placeholder with the real provider value; do not enter only a domain, a dashboard URL, or a shortened URL unless that format appears below.

Host family recognized by the AARExample input formatPanel link options
YouTube
youtube.com
https://www.youtube.com/watch?v=VIDEO_IDSupported Hosts: On. Use only videos whose owner permits playback or embedding.
Vimeo
vimeo.com
https://vimeo.com/VIDEO_IDSupported Hosts: On. The owner must allow playback for your use case.
Dailymotion
dailymotion.com
https://www.dailymotion.com/video/VIDEO_IDSupported Hosts: On.
Google Drive
drive.google.com
https://drive.google.com/file/d/FILE_ID/viewSupported Hosts: On. The file must be shared with the intended audience.
Microsoft OneDrive
1drv.ms
https://1drv.ms/v/SHARE_IDSupported Hosts: On. Use the provider's video share link.
MediaFire
mediafire.com
https://www.mediafire.com/file/FILE_ID/FILE_NAME/fileSupported Hosts: On.
SaveFiles and Streamable
savefiles.com, save-files.com, streamable.com
https://streamable.com/VIDEO_ID
https://savefiles.com/FILE_ID
Supported Hosts: On. Use a public share/watch URL.
FileMoon / Bysekoze
filemoon.sx, filemoon.to, bysekoze.com
https://filemoon.sx/e/VIDEO_ID
https://bysekoze.com/e/VIDEO_ID
Supported Hosts: On.
Yandex Disk
disk.yandex.* or yadi.sk
https://disk.yandex.com/d/SHARE_IDSupported Hosts: On. The share must be publicly reachable.
Yandex Video Preview
yandex.com/video/preview/
https://yandex.com/video/preview/VIDEO_IDSupported Hosts: On.
StreamTape family
streamtape.*, stape.*, strcloud.*
https://streamtape.com/e/VIDEO_ID/Supported Hosts: On.
DoodStream / PlayMogo
dood.*, dooood.*, doodstream.*, d0o0d.com, playmogo.com
https://d0o0d.com/e/VIDEO_ID
https://playmogo.com/e/VIDEO_ID
Supported Hosts: On. Short-lived links are refreshed by the protected resolver when supported.
UQLoad
uqload.vc, uqload.cx
https://uqload.vc/embed-VIDEO_ID.html
https://uqload.vc/e/VIDEO_ID
Supported Hosts: On.
VUpload / FaselHD
vupload.*, faselhd.*
https://vupload.com/VIDEO_IDSupported Hosts: On.
Upstream
upstream.*
https://upstream.to/embed-VIDEO_ID.htmlSupported Hosts: On.
StreamSB family
sbfast.*, dokanhost.*, sbembed4.*, sbvideo.*
https://sbfast.com/e/VIDEO_IDSupported Hosts: On.
LuluStream family
lulustream.com, luluvdo.com, lulu.st, luluvid.com
https://luluvdo.com/e/VIDEO_IDSupported Hosts: On.
StreamRuby-compatible family
streamruby.com, stmruby.com, minochinos.com, forafile.com
https://stmruby.com/e/VIDEO_IDSupported Hosts: On.
Vidara family
vidara.so, vidara.to, vidaraa.cc, mountainpages.cc
https://vidara.so/v/VIDEO_ID
https://mountainpages.cc/e/VIDEO_ID
Supported Hosts: On. Recognized alternate-domain redirects are followed safely.
MixDrop family
mixdrop.sb, mixdrop.co, mixdrop.ag, mixdrop.to, mixdrop.ps, mixdrop.top
https://mixdrop.ps/e/VIDEO_IDSupported Hosts: On.
VidHide / StreamHG family
vidhidevip.com, movearnpre.com, seraphinapl.com, hgcloud.to, audinifer.com, niramirus.com, cybervynx.com, smoothpre.com
https://hgcloud.to/e/VIDEO_ID
https://smoothpre.com/v/VIDEO_ID
Supported Hosts: On.
EmbedWish-compatible family
embedwish.com, streamwish.fun, updown.icu, earnvids.xyz, morencius.com
https://streamwish.fun/e/VIDEO_ID
https://updown.icu/embed-VIDEO_ID.html
Supported Hosts: On.
VOE alternate-domain family
voe.sx, tracylocalschool.com
https://voe.sx/e/VIDEO_ID
https://tracylocalschool.com/e/VIDEO_ID
Supported Hosts: On. Redirects and required playback headers are handled by the protected resolver when available.
Additional 2.4.21 resolver families
NiikaPlayer, BigWarp, VidGuard aliases, GoodStream, DropLoad, RPMHub, and StreamHLS
https://HOST.example/e/VIDEO_ID
https://HOST.example/v/VIDEO_ID
Supported Hosts: On. Use the complete provider URL.
Vidmoly
vidmoly.*
https://vidmoly.to/embed-VIDEO_ID.htmlSupported Hosts: On.
Vidoza
vidoza.*
https://vidoza.net/embed-VIDEO_ID.htmlSupported Hosts: On.
Vidlox
vidlox.*
https://vidlox.me/embed-VIDEO_ID.htmlSupported Hosts: On.
MP4Upload / StreamZZ
mp4upload.*, streamzz.*
https://www.mp4upload.com/embed-VIDEO_ID.htmlSupported Hosts: On.
OK.ru
ok.ru
https://ok.ru/videoembed/VIDEO_IDSupported Hosts: On.
Solidfiles
solidfiles.*
https://www.solidfiles.com/v/FILE_IDSupported Hosts: On.
Sendvid
sendvid.*
https://sendvid.com/VIDEO_IDSupported Hosts: On.
Uptobox / Uptostream
uptobox.*, uptostream.*
https://uptostream.com/VIDEO_IDSupported Hosts: On. Provider/API limitations may apply.
4shared Video
4shared.com/video/ or /web/embed/
https://www.4shared.com/video/VIDEO_ID/FILE_NAME.htmlSupported Hosts: On.
Fembed / VCDN family
fembed.*, vcdn.*
https://fembed.com/v/VIDEO_IDSupported Hosts: On.
FileRIO
filerio.*
https://filerio.in/VIDEO_IDSupported Hosts: On.
HXFile
hxfile.*
https://hxfile.co/embed-VIDEO_ID.htmlSupported Hosts: On. Some configurations require the HXFile API value from panel settings.
NinjaStream
ninjastream.*
https://ninjastream.to/watch/VIDEO_IDSupported Hosts: On.
VidSrc / Dzen
vidsrc.*, dzen.*
https://vidsrc.example/embed/movie/CONTENT_IDSupported Hosts: On. This AAR resolver is separate from the optional IMDb/TMDB embed-provider selector in Player Settings.
Legacy VCDN-style aliases
gdstream, femax20, pocketnow, multiquality, playto1, sbplay, saruch, gavid, kanavid, iplhd, zapurl, dutrag
https://HOST.example/v/VIDEO_ID
https://HOST.example/f/VIDEO_ID
Supported Hosts: On. These are compatibility aliases and may disappear or change independently.
  1. Open the movie, series episode, or anime episode in the admin panel and choose Add New Video Link.
  2. Paste the complete HTTPS provider URL, select its language and quality, and enable Supported Hosts.
  3. Leave HLS off unless the input itself is a direct .m3u8 playlist. Leave Embed off when the AAR resolver should handle the URL.
  4. Save the link, test it on a physical Android device, then test seeking, subtitles, next-episode playback, downloads (when allowed), and casting separately.

Catalog types

Manage movies, series/seasons/episodes, anime, live TV, streaming categories, networks, genres, languages, collections, featured items, previews, upcoming titles, Top 10 and reels.

Home control

Use Content Control to reorder mobile home rails. Disabled and empty rails remain hidden automatically. Configure Top 10 mode and limits in the same workspace.

TMDB Top 10 automation

In Top 10 → Ranking mode, choose TMDB to follow TMDB's global daily trend order. EasyPlex checks each trending TMDB identifier against active movies, series, and anime already stored in your database and displays only local matches. A valid TMDB API key is required; TMDB account requirements, limits, attribution rules, and terms still apply.

Playback

AndroidX Media3 plays buyer-managed HTTPS HLS, DASH and direct media, with subtitles, PiP, auto-play, casting and optional VAST advertising.

Licensed sources only

Add only media you own or are contractually licensed to distribute: your storage, CDN, encoder output, or a provider that explicitly authorizes your use. Optional provider resolvers and automatic embed integrations are compatibility tools only; they do not supply content or distribution rights. Buyers are solely responsible for provider permission, content rights, geographic restrictions and takedown compliance.

HTTPS embeds

The Android embed player requires HTTPS and keeps normal certificate and hostname validation enabled. VidSrc, MegaEmbed and StreamIMDB can be selected under Admin → Settings → Player → Embed services. Provider availability, advertising, privacy behavior, API shape and terms are controlled by the provider and can change independently of EasyPlex.

DRM / licensed ingest

For licensed DASH assets, enable DRM on the movie or episode stream and enter the scheme UUID and HTTPS license-server URL supplied by your DRM vendor (for example Widevine). The app passes those values into Media3’s MediaItem.DrmConfiguration. Store manifests and segments on infrastructure you control, confirm CORS/license authorization, and test on a physical release device. ClearKey is suitable for controlled testing, not strong commercial protection.

IPTV

The streaming area can operate as a managed catalog or M3U playlist manager. Playlist authorization settings protect backend-hosted playlists.

FFmpeg

Enable FFmpeg only when its binaries are installed. Use the admin diagnostics, set binary paths, choose quality presets, and keep a queue worker running for processing jobs.

Android · media compatibility

Supported media hosts and source types

Direct media is not limited to a fixed hostname: the Android app accepts buyer-owned or properly licensed media from any reachable HTTPS origin when the URL returns a supported file or manifest. For HTML watch/embed URLs, use the AAR resolver URL reference above and mark the panel link as Supported Hosts.

Host or sourceAccepted inputTypical EasyPlex useImportant requirements
Your HTTPS server
Nginx, Apache, managed hosting
.m3u8, .mpd, .mp4, .webm, .mkvMovies, episodes, anime, live channels and progressive downloads.Use a valid public TLS certificate, correct MIME types, byte-range responses for progressive files, and URLs reachable by the viewer's device.
CDN or custom media domain
Any provider you are authorized to use
Direct HTTPS manifests, segments, or media filesGlobal delivery, origin protection and scalable playback.The CDN must preserve query strings, range requests, redirects and content types. Chromecast receivers must also be able to reach the final URL.
Amazon S3 and S3-compatible storage
AWS S3, Wasabi, Cloudflare R2, DigitalOcean Spaces, MinIO
Public or time-limited direct HTTPS object URLsStored video files, HLS/DASH packages, artwork and subtitles.Use a public/custom delivery domain or valid signed URLs. Do not place secret access keys in Android. Signed links must remain valid for the expected playback session.
HLS origin or encoder.m3u8 master/media playlists and HTTPS segmentsAdaptive movies, series, anime and live TV.All referenced playlists, keys and segments must use reachable HTTPS URLs. Configure CORS when browser playback or cross-origin tooling also consumes the stream.
MPEG-DASH / licensed DRM provider.mpd manifests, optionally with DRM configurationAdaptive on-demand playback and licensed Widevine workflows.Enter the DRM scheme UUID and HTTPS license-server URL supplied by your vendor. The license server must authorize the app/device request.
YouTubeyoutube.com, youtu.be, and youtube-nocookie.com URLsTrailers, previews, or content the provider permits you to embed.Playback uses the dedicated YouTube/trusted-embed path and remains subject to YouTube API, embedding, advertising and content terms. EasyPlex does not extract raw YouTube media URLs.
Vimeovimeo.com and player.vimeo.com HTTPS embedsAuthorized embedded previews or hosted video.The video owner must allow embedding on the buyer's domain. EasyPlex does not scrape Vimeo pages or bypass privacy controls.
Automatic embed providersVidSrc, MegaEmbed, or StreamIMDB selected in Player SettingsOptional movie and episode embed fallback using IMDb/TMDB identifiers.No provider account, uptime, media, license, or usage permission is included. Buyers must verify that the selected provider and every title are lawful for their territory and use case and comply with the provider's current terms.

Direct means direct

A media URL should return the manifest or media bytes, not an HTML watch page, advertising redirect, captcha, or JavaScript player. Test the final URL outside an authenticated admin browser before publishing it.

HTTPS is required

Release builds reject cleartext HTTP and certificate errors. Use a publicly trusted certificate with the full chain installed; never enable trust-all TLS or hostname bypasses.

Headers and expiring links

If your origin requires authorization headers, cookies, IP binding, or signed query parameters, test seeking, quality changes, subtitles, downloads, background playback and casting. Every referenced segment must remain authorized.

Rights remain mandatory

Technical compatibility is not distribution permission. Use only content and infrastructure you own or are contractually licensed to distribute, and follow provider terms, geographic restrictions and takedown obligations.

Commerce

Subscriptions, payments, and credits

MethodConfigurationOperational requirement
StripeMode, publishable key, secret key and plan price IDsUse test credentials first, then replace them with the matching live credentials before launch.
PayPalMode, client ID, secret and plan IDsKeep sandbox and live credentials separate and confirm each plan maps to the correct environment.
OfflinePayment methods and customer instructionsAn administrator reviews and approves submitted payment requests.
CreditsPackages, content prices and unlock policyChoose permanent unlock or charge on every playback; review transaction history.

Monetization

Advertising

The app includes integrations for AdMob, Meta Audience Network, Unity Ads, Appodeal, IronSource, AppNext, Vungle, AppLovin and Wortise. Enable only networks whose SDK IDs and placements are configured.

App placements

  • Select the active network in Admin → Settings → Ads.
  • Enter banner, interstitial, rewarded and native placement IDs required by that network.
  • Use rewarded ads for unlock flows only after validating callbacks on real devices.
  • Supply the AppLovin SDK key through APPLOVIN_SDK_KEY when AppLovin is enabled.

Player ads

  • Configure VAST/VMAP separately in Player Settings.
  • Select pre-roll, mid-roll, end-roll or all; set a valid mid-roll time.
  • Keep player ads disabled until a test tag completes without blocking content.
  • Follow each network’s consent, privacy, test-ad and store policy requirements.

Production protection

Security model

Security is coordinated between the panel and Android build. A toggle enabled on only one side can make the API unusable.

Transport

HTTPS + certificate pins

Release builds reject cleartext traffic. Pin only certificates you control and always deploy a backup pin.

Request

HMAC + nonce

Protected requests sign the exact method, API path, Unix timestamp, random nonce and SHA-256 raw-body hash.

Session

JWT + device binding

Mobile tokens bind app ID, device ID and session ID. Refresh tokens rotate; reuse can revoke the session.

Response

AES-256-GCM

Optional response envelopes use a per-request derived key and authenticated encryption.

Device

Integrity controls

Root, sniffer, screenshot, VPN/proxy and Play Integrity controls can warn or block according to policy.

Network

Country + rate limits

Allow/block selected countries, cache GeoIP decisions and set global and anomaly API limits.

Signed request contract
X-App-Id: easyplex-mobile
X-Timestamp: 1760000000
X-Nonce: random-url-safe-value
X-Signature: sha256=<hex-hmac>
X-Device-Id: stable-install-id
X-Session-Id: mobile-session-id

HTTP_METHOD_UPPERCASE
/api/path
unix_timestamp_seconds
nonce
sha256(raw_request_body)

Keep it healthy

Operations and maintenance

Clear stale runtime state

php artisan runtime:refresh-state
php artisan optimize:clear

Inspect scheduled tasks

php artisan schedule:list
php artisan schedule:run

Clean completed video jobs

php artisan video:cleanup-jobs --dry-run
php artisan video:cleanup-jobs

Sync subscriptions

php artisan subscriptions:sync-status

Sync new episode flags

php artisan content:sync-new-episodes

Set up subtitle storage

php artisan subtitles:setup

Monitor storage/logs/laravel.log, queue failures, disk space, database growth, payment reconciliation, FFmpeg jobs and certificate expiry. Take automatic database and media backups and test restoration regularly.

Keep queue workers running

Set QUEUE_CONNECTION=database (or a configured Redis connection) and use one process manager, not both. Replace the example paths, PHP binary, and Linux user with values from your server. The worker user must be able to write to storage/ and bootstrap/cache/. Reload the manager after every deployment and run php artisan queue:restart so workers pick up new code safely.

Prepare and verify the queue
cd /var/www/easyplex
php artisan migrate --force
php artisan optimize:clear
php artisan queue:work --once --tries=3 --timeout=300
php artisan queue:failed

Supervisor example

/etc/supervisor/conf.d/easyplex-worker.conf
[program:easyplex-worker]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php /var/www/easyplex/artisan queue:work --sleep=3 --tries=3 --timeout=300 --memory=256
directory=/var/www/easyplex
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/easyplex/storage/logs/worker.log
stdout_logfile_maxbytes=20MB
stdout_logfile_backups=5
stopwaitsecs=360
Enable Supervisor worker
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start easyplex-worker:*
sudo supervisorctl status easyplex-worker:*
sudo tail -f /var/www/easyplex/storage/logs/worker.log

systemd example

/etc/systemd/system/easyplex-worker.service
[Unit]
Description=EasyPlex Laravel queue worker
After=network.target mysql.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/easyplex
ExecStart=/usr/bin/php artisan queue:work --sleep=3 --tries=3 --timeout=300 --memory=256
Restart=always
RestartSec=5
TimeoutStopSec=360
KillSignal=SIGTERM

[Install]
WantedBy=multi-user.target
Enable systemd worker
sudo systemctl daemon-reload
sudo systemctl enable --now easyplex-worker
 sudo systemctl status easyplex-worker
 sudo journalctl -u easyplex-worker -f
Laravel scheduler (separate from queue workers)
* * * * * cd /var/www/easyplex && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

Integration reference

API groups

All paths below are relative to https://your-domain.example/api/. Protected routes may require bearer authentication, mobile signing, session headers, integrity state, and encrypted-response handling.

POSTtokens/mobile/generate

Create a mobile access/refresh-token pair and session ID.

POSTtokens/refresh

Rotate a mobile refresh token.

POSTsecurity/startup-check

Evaluate startup/device security state.

POSTsecurity/integrity/challenge

Create an app-integrity challenge.

GETsettings/{code}

Load the mobile application configuration.

GETmedia/homecontent/{code}

Load ordered home content.

POSTwatch-history/progress

Save profile/device playback progress.

GETwatch-history/continue-watching

Read the current profile’s continue-watching rail.

GETsubscriptions/plans

Return active plans and enabled payment providers.

GETsubscriptions/me

Return authenticated subscription and premium status.

GETreels

Return the paginated reels feed.

POSTmovie-requests/submit

Submit a title request for an authenticated user.

Complete request and response examples

JSON requests use Content-Type: application/json. When mobile request signing is enabled, calculate X-Signature over the exact method, path, timestamp, nonce, and raw JSON body as described in the Security section. Values below are examples only.

Create mobile session · request
POST /api/tokens/mobile/generate HTTP/1.1
Host: stream.example.com
Content-Type: application/json
Accept: application/json
X-App-Id: easyplex-mobile
X-Timestamp: 1760000000
X-Nonce: 4f3f2448-57a1-4c07-9948-4ef8af6d63c2
X-Signature: sha256=CALCULATED_HEX_HMAC
X-Device-Id: 8fe21e37-8a1c-45f0-9085-b992892f8d07

{
  "app_id": "easyplex-mobile",
  "device_id": "8fe21e37-8a1c-45f0-9085-b992892f8d07",
  "package_name": "com.example.easyplex",
  "platform": "android",
  "timestamp": 1760000000,
  "nonce": "4f3f2448-57a1-4c07-9948-4ef8af6d63c2",
  "signature": "9A63192D838D0A4F4F6E4178419293736D574721E1550D4A25F9945D65C73D8A"
}
Create mobile session · 200 response
{
  "success": true,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOi...",
  "refresh_token": "ROTATING_REFRESH_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_expires_in": 2592000,
  "session_id": "b65892dc-474f-45e7-9bec-3280d91ce01f"
}
Save playback progress · request
POST /api/watch-history/progress HTTP/1.1
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
Accept: application/json
X-App-Id: easyplex-mobile
X-Device-Id: 8fe21e37-8a1c-45f0-9085-b992892f8d07
X-Session-Id: b65892dc-474f-45e7-9bec-3280d91ce01f
X-Timestamp: 1760000030
X-Nonce: 15d99c27-0609-42d1-b4ef-9639be41bd84
X-Signature: sha256=CALCULATED_HEX_HMAC

{
  "watchable_type": "App\\Movie",
  "watchable_id": 42,
  "episode_id": null,
  "current_position": 754,
  "duration": 6420,
  "device_id": "8fe21e37-8a1c-45f0-9085-b992892f8d07",
  "profile_id": 3
}
Save playback progress · 200 response
{
  "success": true,
  "message": "Watch progress saved successfully",
  "data": {
    "id": 91,
    "profile_id": 3,
    "progress_percentage": 11.74,
    "current_position": 754,
    "duration": 6420,
    "last_watched_at": "2026-07-29T12:30:30.000000Z"
  }
}

Token validation error · 400

{
  "success": false,
  "message": "Validation failed",
  "errors": {
    "device_id": [
      "The device id field is required."
    ]
  }
}

Invalid APK signature · 401

{
  "success": false,
  "message": "Authentication failed. Invalid APK signature or request parameters.",
  "error_code": "INVALID_SIGNATURE",
  "hint": "Check Laravel logs (storage/logs/laravel.log) for detailed error."
}
Rejected signed request · 401
{
  "success": false,
  "error": {
    "code": "SIGNED_REQUEST_REJECTED",
    "message": "Unauthorized request."
  }
}

Diagnostics

Common failures

Android release fails “SERVER_BASE_URL must contain a valid production HTTPS URL”

Set SERVER_BASE_URL=https://your-domain.example/api/ in the project root gradle.properties. Do not use localhost, a placeholder hostname, or HTTP for release.

The app receives INVALID_SIGNATURE or REPLAY_DETECTED

Copy a fresh matching HMAC secret and app ID from the panel. Confirm the device clock is correct, no proxy changes the request body/path, each request gets a new nonce, and the server cache supports atomic add. Clear/rebuild the Android app after property changes.

Encrypted API responses cannot be decoded

Ensure both sides use the same response-encryption secret, session ID, request nonce and timestamp. Confirm the app asked for encryption and the panel mode is header or always as intended.

Uploads or images fail

Check PHP upload/post limits, writable storage/, the public/storage link, disk configuration, web-server body limits and the generated URL under HTTPS.

Cloudflare R2 uploads fail or save the panel URL

Confirm all five R2 fields are complete, the endpoint uses https://ACCOUNT_ID.r2.cloudflarestorage.com, the bucket name is separate, the API token has Object Read & Write access, and the public URL is reachable. Install the complete 2.4.20 signed update, run the R2 migration, clear Laravel caches, and restart queue workers. Follow the Cloudflare R2 setup guide.

Admin changes do not appear in the app

Save the correct settings tab, then run php artisan runtime:refresh-state and php artisan optimize:clear. Restart queue workers and fully restart the mobile app. Check response-cache settings.

Firebase or OneSignal notifications do not arrive

Match the Firebase package name and Sender ID, replace google-services.json, verify FCM HTTP v1 credentials and the panel’s selected provider, grant Android notification permission, and test on a physical device. For OneSignal, confirm the device appears under Audience → Subscriptions, the App ID matches the same OneSignal app, the API key is app-level and server-side only, and the configured segment name exists. Follow the OneSignal troubleshooting checklist.

App links open in the browser

Validate https://domain/.well-known/assetlinks.json, the final application ID, release SHA-256 fingerprint, HTTPS certificate and manifest host. Reinstall the app after changing link verification data.

Final pass

Production launch checklist

Ready when every layer agrees.

Panel. API. App.
One release.

Back to the beginning ↑
Copied to clipboard