How ActiveCode authentication works
ActiveCode adds device-level security on top of your Player API. Before you build, there's one rule that applies to every request.
mac (Device ID) parameter is required on every URL
Not just API endpoints — it must be included on all player_api.php calls, every streaming URL (Live TV, VOD, Series), and EPG URLs (xmltv.php). Any URL that touches content on an ActiveCode subscription needs it. If appname is configured, include it consistently on all URLs too.
Get a ready-made ActiveCode app for your panel
No API integration, decryption functions, or endless testing. We deliver a fully branded, store-ready app wired to your panel — Device ID on every URL, out of the box.
- Fully branded with your logo & name
- ActiveCode + username/password login ready
- Device ID applied to all URLs automatically
- Application lock (
appname) support - Live TV, VOD & Series with EPG
- Decryption handled internally
- Ready for App Store & Play Store
- Pre-integrated, tested API endpoints
Security layers
ActiveCode protects your streams with two layers. The first is mandatory; the second is optional but recommended for production.
Layer 1 — Device ID Required
The Device ID is a unique identifier that pairs a device to an ActiveCode — a digital fingerprint for each device using your service.
- Pairing: on first auth, the Device ID is paired with the ActiveCode
- Persistence: the same Device ID must be used for every request and URL
- Security: prevents access even if someone obtains the ActiveCode
- Universal: included on every URL when using ActiveCode
- Unique per device
- Stays the same after app reinstallation
- Can be a MAC address or any static hardware ID
- Consistent across all API calls and streaming URLs
Layer 2 — Application lock Optional
Application lock binds an ActiveCode to a specific app. Even with the correct Device ID and ActiveCode, streams are only reachable through your authorized application.
- App-specific access: lock ActiveCodes to your app
- Prevent cloning: stops credentials from working in other apps
- Brand protection: access only through your branded app
- Extra control: a layer beyond device locking
- Add
appnameto all API calls and URLs - Use a consistent app name or serial number
- Can be your app's name or a fixed serial key
- Must stay constant across every request and streaming URL
appname is optional but recommended. If you use it, include it on all URLs — not just API endpoints.Streaming URL authentication
Authentication parameters belong on streaming URLs too, not just API endpoints. Here are the URL shapes for each stream type.
Live stream URL
# Live stream playback URL
http://your.dns:stream_port/live/{ActiveCode}/{DecryptPassword}/{stream_id}.ts?mac={yourdeviceid}
http://your.dns:stream_port/live/{ActiveCode}/{DecryptPassword}/{stream_id}.m3u8?mac={yourdeviceid}
# With Application Lock
http://your.dns:stream_port/live/{ActiveCode}/{DecryptPassword}/{stream_id}.ts?mac={yourdeviceid}&appname={YourAppName}
VOD stream URL
# VOD playback URL
http://your.dns:stream_port/movie/{ActiveCode}/{DecryptPassword}/{vod_id}.mp4?mac={yourdeviceid}
http://your.dns:stream_port/movie/{ActiveCode}/{DecryptPassword}/{vod_id}.mkv?mac={yourdeviceid}
# With Application Lock
http://your.dns:stream_port/movie/{ActiveCode}/{DecryptPassword}/{vod_id}.mp4?mac={yourdeviceid}&appname={YourAppName}
Series episode URL
# Series episode playback URL
http://your.dns:stream_port/series/{ActiveCode}/{DecryptPassword}/{episode_id}.mp4?mac={yourdeviceid}
# With Application Lock
http://your.dns:stream_port/series/{ActiveCode}/{DecryptPassword}/{episode_id}.mp4?mac={yourdeviceid}&appname={YourAppName}
M3U playlist URL
# M3U playlist URL
http://your.dns:stream_port/get.php?username={ActiveCode}&password={DecryptPassword}&type=m3u_plus&output=ts&mac={yourdeviceid}
# With Application Lock
http://your.dns:stream_port/get.php?username={ActiveCode}&password={DecryptPassword}&type=m3u_plus&output=ts&mac={yourdeviceid}&appname={YourAppName}
mac are rejected for ActiveCode subscriptions. Always include the Device ID in every URL.Panel setup
Two settings in your panel power the whole flow. Configure both before testing.
Set up the decryption key
This key decrypts the password string your app receives.
General Settings → General tab → Load Balancing KeySet up the ActiveCode unique password
The unique password associated with an ActiveCode (additional security) that your app retrieves.
General Settings → Streaming tab → Unique PasswordAuthentication flow
Three steps from encrypted password to an authenticated user.
Fetch the encrypted password
Make a GET request to retrieve the encrypted unique password string.
GET http://your.dns:stream_port/player_api.php?action=getactivecodepass
Decrypt the password string
Use the Load Balancing Key from your panel to decrypt the string. Ready-to-use functions are in the Decryption code section below.
Authenticate the user
With the decrypted password, authenticate via the Player API and reuse these credentials on all URLs.
- mac Required — your unique device identifier, on all URLs
- username — use the ActiveCode
- password — use the decrypted unique password
- appname Optional — your app name or fixed serial (if used, on all URLs)
Player API endpoints
Replace the placeholders with your actual values on every request.
{yourdeviceid}Required — your unique device identifier (on all URLs){ActiveCode}— the ActiveCode username{DecryptPassword}— the decrypted password from step 2{YourAppName}Optional — app name or fixed serial for app locking (if used, on all URLs)X— specific ID values (category_id, stream_id, etc.)
mac is required on all URLs for ActiveCode subscriptions. appname is optional, but if used it must appear on every URL consistently.Authentication & user info
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&appname={YourAppName}
Get live stream categories
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_categories
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_categories&appname={YourAppName}
Get all live streams
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_streams
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_streams&appname={YourAppName}
Get live streams by category
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_streams&category_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_live_streams&category_id=X&appname={YourAppName}
Get short EPG for live stream
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_short_epg&stream_id=X
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_short_epg&stream_id=X&limit=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_short_epg&stream_id=X&appname={YourAppName}
Get full EPG for live stream
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_simple_data_table&stream_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_simple_data_table&stream_id=X&appname={YourAppName}
Get VOD categories
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_categories
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_categories&appname={YourAppName}
Get all VOD streams
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_streams
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_streams&appname={YourAppName}
Get VOD streams by category
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_streams&category_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_streams&category_id=X&appname={YourAppName}
Get latest VOD streams Returns 100 latest
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_latest
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_latest&appname={YourAppName}
Get VOD info
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_info&vod_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_vod_info&vod_id=X&appname={YourAppName}
Get series categories
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_categories
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_categories&appname={YourAppName}
Get all series
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series&appname={YourAppName}
Get series by category
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series&category_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series&category_id=X&appname={YourAppName}
Get latest series Returns 100 latest
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_latest
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_latest&appname={YourAppName}
Get series info
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_info&series_id=X
# With Application Lock (Optional)
GET http://your.dns:stream_port/player_api.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&action=get_series_info&series_id=X&appname={YourAppName}
Get ActiveCode password (encrypted)
GET http://your.dns:stream_port/player_api.php?action=getactivecodepass
Full EPG list (XMLTV format)
GET http://your.dns:stream_port/xmltv.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}
# With Application Lock (Optional)
GET http://your.dns:stream_port/xmltv.php?mac={yourdeviceid}&username={ActiveCode}&password={DecryptPassword}&appname={YourAppName}
Decryption code
AES-256-CBC decryption functions. Call decrypt with your Load Balancing Key to decode the API response.
function decrypt($data, $key) {
$key = hash('sha256', $key, true);
$data = base64_decode($data);
$iv = substr($data, 0, 16);
$ciphertext = substr($data, 16);
return openssl_decrypt($ciphertext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.util.Base64;
public class Crypto {
public static String decrypt(String data, String key) throws Exception {
byte[] keyBytes = MessageDigest.getInstance("SHA-256").digest(key.getBytes());
byte[] combined = Base64.getDecoder().decode(data);
byte[] iv = new byte[16];
byte[] ciphertext = new byte[combined.length - 16];
System.arraycopy(combined, 0, iv, 0, 16);
System.arraycopy(combined, 16, ciphertext, 0, ciphertext.length);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(iv));
return new String(cipher.doFinal(ciphertext));
}
}
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import java.security.MessageDigest
import java.util.Base64
object Crypto {
fun decrypt(data: String, key: String): String {
val keyBytes = MessageDigest.getInstance("SHA-256").digest(key.toByteArray())
val combined = Base64.getDecoder().decode(data)
val iv = combined.copyOfRange(0, 16)
val ciphertext = combined.copyOfRange(16, combined.size)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(keyBytes, "AES"), IvParameterSpec(iv))
return String(cipher.doFinal(ciphertext))
}
}
const crypto = require('crypto');
function decrypt(data, key) {
const keyBuf = crypto.createHash('sha256').update(key).digest();
const combined = Buffer.from(data, 'base64');
const iv = combined.subarray(0, 16);
const ciphertext = combined.subarray(16);
const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuf, iv);
let plaintext = decipher.update(ciphertext);
plaintext = Buffer.concat([plaintext, decipher.final()]);
return plaintext.toString('utf8');
}
/*
Add dependencies to your pubspec.yaml:
dependencies:
encrypt: ^5.0.1
crypto: ^3.0.1
*/
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
String decrypt(String data, String key) {
final keyBytes = sha256.convert(utf8.encode(key)).bytes;
final combined = base64.decode(data);
final iv = IV(Uint8List.fromList(combined.sublist(0, 16)));
final ciphertext = Encrypted(Uint8List.fromList(combined.sublist(16)));
final encrypter = Encrypter(AES(Key(Uint8List.fromList(keyBytes)), mode: AESMode.cbc));
return encrypter.decrypt(ciphertext, iv: iv);
}
Best practices
The critical rules, the mistakes to avoid, and how to build it right.
Critical requirements
- Device ID (mac) is mandatory — include it in every single URL for ActiveCode subscriptions
- Consistency is key — use the same Device ID across all requests for a given device
- Application lock — if you use
appname, include it on all URLs consistently - Streaming URLs — add auth parameters to streaming URLs, not just API endpoints
- M3U playlists — ensure the
macparameter is included when generating or using them
- Forgetting
macon streaming URLs - Using different Device IDs for API calls and streaming URLs
- Not including
appnameconsistently when it's configured - Hardcoding auth parameters instead of adding them dynamically
- Not URL-encoding parameters when building URLs
- Store the Device ID securely and persistently on the device
- Use a central function to append auth parameters to all URLs
- Test with both API endpoints and streaming URLs
- Monitor failed authentication attempts to catch security issues
- Keep your Load Balancing Key secure — never expose it in client-side code