Skip to content

Reseller API

For partner servers and panels to activate, renew and manage UTM Play TVs straight from their own system.

What it is

The reseller API lets your IPTV server's panel act on your customers' TVs in UTM Play: renew a MAC's license, push the playlist (M3U) to the TV, change the customer name, and look up devices, expiry dates and credits used.

Access is by token. Each token belongs to one partner server and is issued by the UTM Play team; the API does not create tokens.

Base URL

Routes live under /api/… on either address below; both answer the same way.

  • https://api2.utmplay.wtf
  • https://utmplay.wtf

Use HTTPS. Every route allows CORS (Access-Control-Allow-Origin: *).

Authentication

Authorization: SEU_TOKEN

Send the token in the Authorization header, with no prefix. Routes also accept "Bearer YOUR_TOKEN" except get_device, which only accepts the bare token: always send the bare token.

/api/login checks the token and tells you which server it belongs to; it does not issue a new token and is not required before other calls.

Format

  • POST bodies are JSON (Content-Type: application/json), except delete_mac, which takes the MAC in the URL.
  • The MAC is matched exactly as stored: lowercase hex with colons, e.g. 00:1a:2b:3c:4d:5e.
  • Successful responses carry JSON (some with Content-Type text/plain, inherited from the original API) or a short sentence of text. Errors are plain text, one line, with the HTTP error status.
  • Expiry dates are YYYY-MM-DD; 9999-12-31 means lifetime.

Limits

  • There is no general per-minute request limit. Please be gentle: run large batches sequentially, not in parallel.
  • Wrong device code (device_key) on renew: after 5 failures on the same MAC, or 20 failures from the same server, within 1 hour, renewals are locked for 1 hour and answer 404 "Device not found", even with the right code.
  • On a token with a platform list, routes that change a device refuse devices from other platforms (see below).

Allowed platforms per token

The UTM Play team can limit a token to some platforms (for example, only Samsung and LG). With no limit set, the token works for all of them, which is the default.

With a limit, the routes that change a device refuse a MAC whose recorded platform is not on the list, before writing anything or counting credits: 403 with the message below, ending with the device's platform (samsung, lg, roku, android, androidtv, firetv, ios…).

A device with no recorded platform is never refused. Lookups (get_device, device_expiration, count_credits, count_macs) and login are unchanged.

403
Platform not allowed for this token: roku

Affected routes: renew, add_playlist, update_client_name and delete_mac.

Errors common to every route with a token

On top of each route's own errors:

  • 401Missing Authorization header.
    Authorization token is required
  • 403Unknown token.
    Forbidden
  • 405Wrong method (e.g. GET on a POST route). Empty body.
  • 500Internal failure; try again later.
    Internal Server Error
POST/api/loginLookup

Check the token

Checks that the token is valid and returns the server it belongs to. No Authorization header needed.

Parameters

tokenstring · JSON
Required: yesYour token.

Example

curl -X POST https://api2.utmplay.wtf/api/login \
  -H 'Content-Type: application/json' \
  -d '{"token":"SEU_TOKEN"}'

Success

  • 200Valid token.
    {"status":"success", "role":"client", "server":"MeuServidor"}

Errors

  • 400No token, or a body that is not JSON.
    Token is required
  • 403Unknown token.
    Invalid token or IP not allowed
POST/api/renewChanges the device

Activate or renew a MAC

Renews the TV license and stores the renewal's credit on the device: semi-annual = 1, annual = 2, lifetime = 3 (count_credits sums this value over your devices). If the license is still valid the new period starts at the current expiry date; if it has expired, from today.

Needs the MAC and the device code (device_key, 6 digits shown on the TV). The MAC must already exist: the TV must have opened UTM Play at least once. The device then belongs to your server.

Parameters

mac_addressstring · JSON
Required: yesTV MAC.
device_keystring · JSON
Required: yesDevice code shown on the TV.
renew_typestring · JSON
Required: yessemi_annual (6 months), annual (1 year) or lifetime.
revenda_idint · JSON
Required: noReseller id in your system (number). Used by count_credits and get_device.
clientestring · JSON
Required: noCustomer name, only echoed in the response.
reseller_namestring · JSON
Required: noAccepted for compatibility; not stored.

Example

curl -X POST https://api2.utmplay.wtf/api/renew \
  -H 'Authorization: SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"mac_address":"00:1a:2b:3c:4d:5e","device_key":"123456","renew_type":"annual","revenda_id":42,"cliente":"joao"}'

Success

  • 200Renewed. Updated device.
    {"id":"66f1c2a9e4b0a1b2c3d4e5f6","is_trial":1,"credit_count":2,"mac_address":"00:1a:2b:3c:4d:5e","app_type":"samsung","device_key":"123456","expire_date":"2027-10-12","revenda_id":42,"server":"MeuServidor","cliente":"joao","updated_at":"2026-10-06T00:27:49.952547665+02:00"}

Errors

  • 400Invalid body: the message comes from the JSON decoder, e.g. revenda_id sent as text.
    json: cannot unmarshal string into Go struct field .revenda_id of type int
  • 400Unknown renew_type.
    Invalid renew_type
  • 400The device is already lifetime.
    Renewal not allowed. Device has lifetime license.
  • 403Device platform not in the token's list.
    Platform not allowed for this token: roku
  • 404Unknown MAC, wrong code, or locked after wrong codes (see Limits).
    Device not found
POST/api/add_playlistChanges the device

Push the playlist to the TV

Stores the playlist URL (M3U) on the TV: replaces the device's first playlist or creates one if there is none. The device then belongs to your server; the customer name is taken from the URL's username= when present.

The response tells whether the playlist was created (InsertedID) or replaced (MatchedCount).

Parameters

device_idstring · JSON
Required: yesTV MAC.
urlstring · JSON
Required: yesM3U playlist URL.
revenda_idint · JSON
Required: noReseller id in your system (number).
reseller_namestring · JSON
Required: noReseller name, stored with a newly created playlist.

Example

curl -X POST https://api2.utmplay.wtf/api/add_playlist \
  -H 'Authorization: SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"device_id":"00:1a:2b:3c:4d:5e","url":"http://exemplo.com:8080/get.php?username=joao&password=1234&type=m3u_plus&output=ts","revenda_id":42,"reseller_name":"Revenda X"}'

Success

  • 200Playlist created.
    {"InsertedID":"6ac42465ca34be2c60e18662"}
  • 200Existing playlist replaced.
    {"MatchedCount":1,"ModifiedCount":1,"UpsertedCount":0,"UpsertedID":null}

Errors

  • 400Invalid body (JSON decoder message, as in renew).
    json: cannot unmarshal …
  • 403Device platform not in the token's list.
    Platform not allowed for this token: roku
  • 404Unknown MAC.
    Device not found
GET/api/get_deviceLookup

List and search devices

Lists YOUR server's devices, with filters and paging. Each item carries the number of devices matching the filter (total). With no results the response is null.

This route requires the bare token in Authorization (no "Bearer").

Parameters

macstring · URL
Required: noMAC prefix (case-insensitive).
device_keystring · URL
Required: noDevice code prefix.
clientestring · URL
Required: noCustomer name prefix.
revenda_idint · URL
Required: noExact reseller.
app_typestring · URL
Required: noExact platform (samsung, lg, roku…).
statusstring · URL
Required: noactive (expires after today) or expired.
pageint · URL
Required: noPage, from 1 (default 1).
limitint · URL
Required: noItems per page (default 10).

Example

curl 'https://api2.utmplay.wtf/api/get_device?mac=00:1a&status=active&page=1&limit=10' \
  -H 'Authorization: SEU_TOKEN'

Success

  • 200Devices found (application/json).
    [{"__v":0,"_id":"66f1c2a9e4b0a1b2c3d4e5f6","app_type":"samsung","cliente":"joao","credit_count":2,"device_key":"123456","expire_date":"2027-10-12","is_trial":1,"mac_address":"00:1a:2b:3c:4d:5e","revenda_id":42,"server":"MeuServidor","total":1,"updated_at":"2026-10-06T00:27:49.952+02:00"}]
  • 200No device.
    null

Errors

  • 401Missing Authorization header.
    Authorization token is required
  • 401Unknown token, or sent with "Bearer ".
    Invalid token
  • 404Invalid text filter (regular-expression special characters).
    Failed to find devices
GET/api/device_expirationLookup

Expiry date of a MAC

Returns the device's license expiry date.

Parameters

mac_addressstring · URL
Required: yesTV MAC.

Example

curl 'https://api2.utmplay.wtf/api/device_expiration?mac_address=00%3A1a%3A2b%3A3c%3A4d%3A5e' \
  -H 'Authorization: SEU_TOKEN'

Success

  • 200Device found.
    {"expire_date":"2027-10-12"}

Errors

  • 400Missing mac_address.
    mac_address is required
  • 404Unknown MAC.
    Device not found
GET/api/count_creditsLookup

Credits used

Sums the credit of the latest renewal of each of your server's devices (semi-annual = 1, annual = 2, lifetime = 3). Without revenda_id, one server total; with revenda_id=all, one total per reseller; with a number, only that reseller. With nothing to sum the response is null.

Parameters

daysint · URL
Required: noOnly devices changed in the last N days.
revenda_idint or "all" · URL
Required: noall = group by reseller; number = only that reseller.

Example

curl 'https://api2.utmplay.wtf/api/count_credits?days=30&revenda_id=all' \
  -H 'Authorization: SEU_TOKEN'

Success

  • 200Without revenda_id.
    [{"_id":"MeuServidor","total_credits":2}]
  • 200With revenda_id=all or a number.
    [{"_id":42,"total_credits":2}]
  • 200Nothing to sum.
    null

Errors

  • 400days is not a number.
    Invalid days parameter
  • 400revenda_id is neither a number nor all.
    Invalid revenda_id parameter
GET/api/count_macsLookup

Number of devices

How many devices are linked to your server.

Parameters

No parameters.

Example

curl https://api2.utmplay.wtf/api/count_macs \
  -H 'Authorization: SEU_TOKEN'

Success

  • 200Server total.
    {"mac_count":1}

Errors

—

POST/api/update_client_nameChanges the device

Change the customer name or code

Changes the customer name and/or the device code (device_key). Send at least one of them. Changing the code changes what the TV needs to be renewed.

The response is the same when the MAC does not exist (nothing is changed).

Parameters

mac_addressstring · JSON
Required: yesTV MAC.
new_client_namestring · JSON
Required: noNew customer name.
device_keystring · JSON
Required: noNew device code, digits only.

Example

curl -X POST https://api2.utmplay.wtf/api/update_client_name \
  -H 'Authorization: SEU_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"mac_address":"00:1a:2b:3c:4d:5e","new_client_name":"maria"}'

Success

  • 200Request accepted.
    Client details updated successfully

Errors

  • 400Body is not JSON.
    Failed to parse request body
  • 400device_key has non-digits.
    Device key must be numeric
  • 400Neither new_client_name nor device_key.
    No fields provided for update
  • 403Device platform not in the token's list.
    Platform not allowed for this token: roku
POST/api/delete_macChanges the device

Remove a MAC

Removes the device from your server. The MAC goes in the URL (?mac=), no body. Only removes devices linked to your server.

Warning: Removing cannot be undone through the API: the device goes away with its license and playlists. If the TV opens the app again it comes back as a new device, without the previous license, and must be activated again. Double-check the MAC.

Parameters

macstring · URL
Required: yesTV MAC.

Example

curl -X POST 'https://api2.utmplay.wtf/api/delete_mac?mac=00%3A1a%3A2b%3A3c%3A4d%3A5e' \
  -H 'Authorization: SEU_TOKEN'

Success

  • 200Removed.
    Device deleted successfully, but no associated playlist found.

Errors

  • 400Missing mac parameter.
    MAC address is required
  • 403Device platform not in the token's list.
    Platform not allowed for this token: roku
  • 404Unknown MAC or one from another server.
    No device or playlist found to delete