Authentication and transport contract
Android/mobile API
Base URL: https://your-domain.example/api/. Obtain a rotating bearer token from POST tokens/mobile/generate. Protected calls send the bearer token plus the session/device headers. If signing is enabled, sign the exact method, path, timestamp, nonce, and raw body.
Accept: application/json
Authorization: Bearer ACCESS_TOKEN
X-App-Id: easyplex-mobile
X-Device-Id: STABLE_INSTALL_ID
X-Session-Id: MOBILE_SESSION_ID
X-Timestamp: UNIX_SECONDS
X-Nonce: UNIQUE_RANDOM_VALUE
X-Signature: sha256=HEX_HMAC
Admin panel API
Admin endpoints are internal browser endpoints, not a public third-party API. Sign in through the panel first. Laravel sends a session cookie and XSRF-TOKEN cookie; state-changing AJAX requests must include the decoded token as X-XSRF-TOKEN.
Accept: application/json
Content-Type: application/json
Cookie: easyp_cpanel_session=...; XSRF-TOKEN=...
X-XSRF-TOKEN: DECODED_XSRF_COOKIE
X-Requested-With: XMLHttpRequest
Do not expose credentials. Never publish access tokens, HMAC/encryption secrets, admin session cookies, payment keys, purchase codes, private signing material, or production database values. Example values here are placeholders.
Mobile request and response examples
1. Generate a mobile session
POST /api/tokens/mobile/generate
Content-Type: application/json
{
"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": "APK_CERTIFICATE_SHA256_64_HEX"
}
200 OK
{
"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"
}
2. Sign in a user
POST /api/login
Content-Type: application/json
Authorization: Bearer MOBILE_ACCESS_TOKEN
{
"email": "[email protected]",
"password": "A-strong-demo-password"
}
200 OK
{
"success": true,
"message": "Login successful",
"user": {
"id": 12,
"name": "Demo Buyer",
"email": "[email protected]",
"premuim": 0
}
}
3. Load application settings
GET /api/settings/en
Accept: application/json
Authorization: Bearer ACCESS_TOKEN
200 OK
{
"app_name": "EasyPlex",
"app_version": "2.4",
"tmdb_lang": "en",
"enable_download": 1,
"enable_ads": 0,
"default_theme": "dark"
}
4. Load the home catalog
GET /api/media/homecontent/en
Accept: application/json
Authorization: Bearer ACCESS_TOKEN
200 OK
{
"featured": [],
"movies": {
"data": [
{
"id": 42,
"name": "Licensed Feature",
"poster_path": "https://cdn.example.com/posters/42.jpg"
}
]
},
"series": { "data": [] },
"streaming": { "data": [] }
}
5. Search catalog content
GET /api/search?query=licensed
Accept: application/json
Authorization: Bearer ACCESS_TOKEN
200 OK
{
"movies": [{ "id": 42, "name": "Licensed Feature" }],
"series": [],
"animes": [],
"streaming": []
}
6. Save playback progress
POST /api/watch-history/progress
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN
{
"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
}
200 OK
{
"success": true,
"message": "Watch progress saved",
"progress_percentage": 11.74
}
7. Create a profile
POST /api/profiles
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN
{
"name": "Kids",
"avatar": "avatar-3",
"is_kids": true
}
201 Created
{
"success": true,
"profile": {
"id": 3,
"name": "Kids",
"avatar": "avatar-3",
"is_kids": true
}
}
8. Read subscription state
GET /api/subscriptions/me
Accept: application/json
Authorization: Bearer ACCESS_TOKEN
200 OK
{
"success": true,
"is_premium": true,
"subscription": {
"plan": "Monthly",
"status": "active",
"ends_at": "2026-08-29T00:00:00Z"
}
}
Exact catalog fields vary with enabled modules and settings. Use the supplied Android models as the authoritative consumer contract and test against a staging installation before release.
Admin panel request and response examples
These calls are made by the Vue administration panel after login. Paths are relative to the Laravel public URL and are protected by the panel’s session, authorization, CSRF, and license middleware.
Read settings
GET /admin/settings/data
Accept: application/json
Cookie: easyp_cpanel_session=...
200 OK
{
"id": 1,
"app_name": "EasyPlex",
"app_version": "2.4",
"enable_security": 1,
"enable_download": 1
}
Update settings
PUT /admin/settings/update/1
Content-Type: application/json
X-XSRF-TOKEN: DECODED_XSRF_COOKIE
Cookie: easyp_cpanel_session=...; XSRF-TOKEN=...
{
"app_name": "My Licensed Service",
"default_theme": "dark",
"enable_download": 1
}
200 OK
{
"status": "success",
"message": "Settings updated successfully"
}
List movies
GET /admin/movies/dataweb?page=1
Accept: application/json
Cookie: easyp_cpanel_session=...
200 OK
{
"current_page": 1,
"data": [
{
"id": 42,
"name": "Licensed Feature",
"active": 1,
"premuim": 0
}
],
"last_page": 1,
"total": 1
}
Create a movie
POST /admin/moviesmedia/storemovie
Content-Type: application/json
X-XSRF-TOKEN: DECODED_XSRF_COOKIE
{
"name": "Licensed Feature",
"tmdb_id": 12345,
"overview": "Licensed description.",
"poster_path": "https://cdn.example.com/poster.jpg",
"backdrop_path": "https://cdn.example.com/backdrop.jpg",
"release_date": "2026-07-29",
"active": 1,
"premuim": 0
}
201 Created
{
"status": "success",
"message": "Movie created successfully",
"id": 42
}
Export Android properties
GET /admin/settings/mobile-gradle-properties
Accept: text/plain
Cookie: easyp_cpanel_session=...
200 OK
Content-Disposition: attachment; filename="gradle.properties"
SERVER_BASE_URL=https://stream.example.com/api/
MOBILE_APP_ID=easyplex-mobile
MOBILE_API_HMAC_SECRET=...
Create database backup
POST /admin/settings/database-backup
X-XSRF-TOKEN: DECODED_XSRF_COOKIE
Cookie: easyp_cpanel_session=...
200 OK
Content-Type: application/zip
Content-Disposition: attachment; filename="easyplex-backup-....zip"
[binary ZIP response]
Standard success and error shapes
400 · token request validation
{
"success": false,
"message": "Validation failed",
"errors": {
"device_id": ["The device id field is required."]
}
}
401 · invalid APK binding
{
"success": false,
"message": "Authentication failed. Invalid APK signature or request parameters.",
"error_code": "INVALID_SIGNATURE",
"hint": "Check Laravel logs for validation details."
}
401 · signed request rejected
{
"success": false,
"error": {
"code": "SIGNED_REQUEST_REJECTED",
"message": "Unauthorized request."
}
}
401 · session expired
{
"message": "Unauthenticated."
}
403 · not authorized
{
"message": "This action is unauthorized."
}
422 · form validation
{
"message": "The given data was invalid.",
"errors": {
"name": ["The name field is required."],
"tmdb_id": ["The tmdb id must be an integer."]
}
}
429 · rate limit
{
"message": "Too Many Attempts."
}
500 · server failure
{
"message": "Server Error"
}
Production servers must use APP_DEBUG=false. A production error response must never include stack traces, SQL, absolute paths, secrets, or environment values.