AnyTV Provider API

Connect your own management system to AnyTV. Everything you do by hand in the provider console, your system can do automatically: look at a customer's device, activate AnyTV Pro on it with your credits, send the customer their playlist, update it, move it to a new host, and remove it when the subscription ends.

The API is plain HTTPS and JSON. There is no SDK to install. Every example on this site is available in cURL, Node.js, PHP and Python. Pick your language once, in any code box, and the whole site follows.

Base URL

  • All requests use HTTPS. Plain HTTP is refused with 400 https_required.
  • Request and response bodies are JSON. Send Content-Type: application/json with every body. Bodies are limited to 16 KB.
  • The API is for servers only. An API key must never be placed in a web page or an app.
  • Field names are snake_case. Timestamps are UTC in ISO 8601. Money never appears here; credits do, see Credits and units.

You are isolated from every other provider. Your key can only see and change what belongs to your account. Nothing in a path or a body can reach another provider's device, activation or playlist: the answer is 404 as if it did not exist.

AnyTV is a player. It supplies no channels or playlists. You deliver your own playlists to customers who chose you, and you confirmed in the console that you hold the rights to what you deliver.

Quickstart

From nothing to a customer watching, in five steps.

  1. Create an API key. Sign in to the provider console, open API keys, then Create a key. Confirm with your password. The key is shown once, so copy it straight into your server's secrets. See Authentication.
  2. Check that it works. Call GET /v1/me. You get your provider name, your caps and what your account may do right now.
  3. Ask the customer for the code. On the TV they open AnyTV and choose Send to this TV. The screen shows a short code and a QR code. The code lasts a few minutes.
  4. Look at the device. Send the code to POST /v1/devices/preview. You get a device_ref that is yours to keep for this device, and whether it can be activated.
  5. Send the playlist, or activate Pro. POST /v1/deliveries sends a playlist for free. POST /v1/activations unlocks AnyTV Pro on the device for a year or two with your credits, and you can send the playlist in the same breath with POST /v1/activations/{id}/deliveries.

Testing. There is no separate test mode. Test with a spare device of your own: preview it, send a playlist, activate it, then undo within 72 hours and the credits come back.

How it works

  1. The customer shows a code. AnyTV on the TV mints a short lived code tied to that installation. Nothing about the customer leaves the device: you never see an account, an email or an address.
  2. You preview. The code resolves to a device_ref, an identifier that is specific to your provider account. The same TV has a different device_ref for every provider. Save it next to your customer; it does not expire.
  3. You deliver or activate. A delivery waits with status pending until the app picks it up on its next check in, usually within a minute, and becomes delivered. An activation reserves your credits, AnyTV's billing confirms it, and the device has Pro. In the rare case billing is slow you get 202 processing and the activation finishes on its own.
  4. The customer stays in charge. They can remove your provider from their device at any time. Your playlists leave, the activation ends as released, and further calls for that device answer 409 device_blocked_provider until they allow you again.

The most common first error is 404 device_not_found. The code expired or was mistyped. Ask the customer to open Send to this TV again for a fresh one. Do not retry in a loop, see Rate limits and caps.

A client you can copy

You do not need a library, but you do want four things in one place: your key, a timeout, retries, and clean errors. The helper on the right does all four in about thirty lines. Copy it into your project and the rest of your code becomes one line per call.

  • It reads the key from the ANYTV_API_KEY environment variable.
  • It retries only what is temporary: network failures, 5xx, 409 request_in_progress and short 429 waits. It never sits out a daily cap.
  • It refuses an activation write without an Idempotency-Key, because only the key makes a retry safe.
  • It never logs anything. Keep it that way: the key and your customers' playlist passwords pass through it.
  • It turns error responses into exceptions that carry the error code, so you can branch on device_not_found and friends.

Authentication

Every request carries your API key in the Authorization header as a bearer token. There are no sessions, no cookies and no login call.

Creating a key

  1. Sign in to the provider console as an owner or admin and open API keys.
  2. Choose Create a key. Give it a name you will recognise later, for example "Billing system".
  3. Choose its scopes. A key can only hold scopes your own role has. See Scopes.
  4. Optionally restrict the key to your servers' IP addresses: exact addresses, up to 20.
  5. Optionally set an expiry, 1 to 730 days. We recommend a year, with a reminder to replace the key before then.
  6. Confirm with your password. Copy the key. It is shown once. AnyTV stores only a one way hash and cannot show it to you again. If you lose it, revoke it and create a new one.

Replacing a key without downtime

Your account can hold more than one active key (the number is one of your caps, see GET /v1/me). Create the second key, switch your system to it, confirm that it works, then revoke the first.

A missing, malformed, unknown, revoked or expired key always gets the same answer: 401 invalid_api_key. A key used from an address outside its allowlist gets 403 ip_not_allowed.

Scopes

Each key carries one or more scopes. Give a key only what it needs. A reporting tool, for example, needs devices:read and credits:read and nothing else.

ScopeAllows
credits:readYour balance and ledger.
devices:readPreview a device by its code, retrieve it by its device_ref.
activations:readList and retrieve activations.
activations:writeActivate, extend, move, undo and revoke.
deliveries:readList and retrieve playlists you sent.
deliveries:writeSend, update, remove and bulk move playlists.

Calling an endpoint without its scope returns 403 insufficient_scope. GET /v1/me needs no scope.

Some things are not in the API at all. Your password, your team, your API keys, your company details and buying credits can only be managed in the console by a person who is signed in, with a second factor. A leaked key can never take over your account or spend money.

Keeping keys safe

A key is a password for your customers' devices and your credits. Treat it like one.

  • Server only. Keep it in an environment variable or a secrets manager. Never in a web page, a mobile app, a spreadsheet or a chat message.
  • Never in source control. Keys start with atv_live_ so that secret scanners can spot one that was committed by mistake.
  • One key per system. If two systems talk to AnyTV, give each its own key, so you can revoke one without stopping the other.
  • Watch the last used column. The console shows when each key was last used. A time you cannot explain means the key should be revoked now.
  • Lock it to your IP if you can. If your server has fixed IP addresses, list them when you create the key.
  • Revoking is instant. The very next request with a revoked key fails. AnyTV staff can also revoke a key for you in an emergency.
  • Never log it. Keep the Authorization header, request bodies and playlist URLs out of your logs and error reports. They contain the key and your customers' playlist passwords.
  • No personal data in references. external_ref, playlist names and Idempotency-Keys are stored as plain text. Use an order or customer number, never a person's name or a password.
  • On 401 invalid_api_key, stop. Do not retry. Alert a person: the key was revoked, has expired or is wrong.

If a key may have leaked: revoke it in the console first, then create a new one. Afterwards, read your ledger and your activations for anything you do not recognise. The console's audit trail shows every call that changed something.

Errors

AnyTV uses normal HTTP status codes. 2xx means it worked. 4xx means the request needs to change before it can work. 5xx means something went wrong on our side and the same request can be retried.

Every error body carries error, which is stable, and usually message, which is for people and may be reworded. When waiting helps, retry_after (seconds) is in the body and in the Retry-After header. When your standing is the cause, reason names the step that unblocks it, the same word the console shows. Write your code against error.

Every route

StatuserrorMeaning
400https_requiredYou used plain HTTP. Switch to HTTPS and revoke the key you sent, it may have been seen.
400invalid_bodyThe body is not a JSON object.
400idempotency_key_requiredThis route needs an Idempotency-Key header.
400invalid_idempotency_keyThe key is shorter than 8, longer than 128, or uses other characters than letters, digits and _ - : .
400invalid_limit, invalid_cursorA list parameter is not valid. limit is 1 to 100; start again without the cursor.
401invalid_api_keyMissing, malformed, unknown, revoked or expired key.
403insufficient_scopeThe key lacks the scope the route needs.
403ip_not_allowedThe key is restricted to other IP addresses.
403provider_not_activeYour account is frozen, suspended or closed, or onboarding is not finished. reason says which.
403approval_required, kyc_required, not_allowlisted, not_operatorYour standing does not allow this yet. See Your standing.
404not_foundNo such route or resource, or it belongs to another provider.
409request_in_progressThe same Idempotency-Key is still being processed. Retry in a moment.
413body_too_largeBodies are limited to 16 KB.
415unsupported_media_typeSend Content-Type: application/json.
422idempotency_key_reusedThat Idempotency-Key was used before with a different request.
429rate_limitedWait retry_after seconds. See Rate limits and caps.
503api_unavailable, billing_unavailableTemporary. Retry later, with the same Idempotency-Key where one was used.
503activations_disabled, deliveries_disabledAnyTV paused that part of the program. Reads, removals, undo and revoke keep working.
5xxnot JSONAn error page from the network may not be JSON at all. Do not assume a JSON body on 5xx.

Endpoint specific errors, such as device_not_found or insufficient_credits, are listed with each endpoint.

What to retry

  • Retry: network failures, timeouts, 429 with a short wait, 409 request_in_progress and any 5xx. Wait longer each time, and send the same Idempotency-Key.
  • Do not retry unchanged: every other 4xx. The request itself has to change.

Safe retries

Networks fail. When a request times out, you cannot know whether AnyTV received it. Sending it again could spend credits twice. The Idempotency-Key header solves this.

The header is required on every call that can spend or return credits: activate, extend, move, undo and revoke. It is accepted on sending, updating and removing a playlist. Use a value that is unique to the operation: your own order number works well, order-1001-activate, order-1001-playlist.

  • If the first request succeeded, the retry returns the very same response, marked with the header Idempotent-Replayed: true. Nothing is done twice. An activation replay answers 200 instead of 201.
  • If the first request failed, the retry runs normally.
  • Same key, different request returns 422 idempotency_key_reused. This catches bugs where two operations share a key.
  • First request still running returns 409 request_in_progress. Wait a moment and retry.
  • An activation that answered 202 processing finishes on its own. Retrying with the same key returns its current state; a new key would start a new activation and be refused with 409 already_activated_by_you once the first one is active.

Keys are 8 to 128 characters, made of letters, digits and _ - : . They are remembered for 24 hours and are private to your account.

Rate limits and caps

LimitApplies to
120 requests per minuteEach API key
300 requests per minuteEach IP address you call from, all keys together
60 writes per minuteEach API key: previews, activations, playlist sends, updates and removals together
1 bulk host move per minuteYour account
New devices per dayYour account's cap, shown in GET /v1/me as new_devices_per_day. A device you never sent anything to counts once, on its first playlist.
Activations per dayYour account's cap, activations_per_day.
Live playlists per deviceYour account's cap, live_deliveries_per_device.

When you are over a limit you receive 429 with the seconds to wait in retry_after and in the Retry-After header. A minute limit answers rate_limited; a daily cap answers new_device_cap_reached or activation_cap_reached with a wait of up to an hour. Do not sleep through a daily cap inside a request. Give up and try tomorrow.

Caps protect the program, not you from yourself. They are set by AnyTV per provider and grow with a track record. If your business needs more, ask through the console.

Pagination

Lists are paged with a cursor. Ask for up to limit rows (1 to 100, 50 by default); the response carries next_cursor, which is null on the last page. Send it back as cursor for the next page. A cursor is opaque and private to your account; a reused or edited cursor answers 400 invalid_cursor.

Credits and units

You buy credits in the console. The API counts them in units: ten units are one credit, so a balance of 184 units is 18.4 credits. Every balance also carries available_credits as text, for display.

TermCodeCosts
One year of ProP1Y10 units (1 credit)
Two years of ProP2Y18 units (1.8 credits)

An activation reserves the units first and commits them when AnyTV's billing confirms, which is usually inside the same request. A failed activation releases them. An undo within 72 hours refunds them. Your ledger shows every move.

Your standing

Whether a call is allowed depends on your account's standing, which GET /v1/me reports as capabilities. Reads, removals, undo and revoke always work, in every state. New work needs the capability:

CapabilityNeeded for
deliverSending and updating playlists, bulk host moves.
activateActivating, extending and moving Pro.
keysCreating keys (console only).
buy_creditsBuying credits (console only).

A blocked capability carries a reason, and a refused call carries the same word:

reasonWhat it means
email_unverified, terms_required, attestation_requiredFinish onboarding in the console.
approval_pendingAnyTV has not approved your account yet.
kyc_required, kyc_pending, kyc_rejectedThe identity check before credits can be used.
not_allowlistedPaid activations are not open for your account yet.
frozen, suspended, account_closedYour account cannot start new work. Contact AnyTV.
program_pausedAnyTV paused that part of the program for everyone.
daily_delivery_cap, daily_activation_capToday's cap is reached.
insufficient_creditsBuy credits in the console.

Preview a device

POST/v1/devices/previewdevices:read

Resolves the code on the customer's TV to a device_ref and tells you what you can do with the device. Call it before activating: it is free, and it tells you about a Pro the customer already has or an activation by another provider before you spend anything.

Body

codestringrequired

The code on the TV. Dashes, spaces and lower case are accepted.

Returns

device_refstring

Your reference for this device. Save it: it lets you deliver and activate later without a new code, and it is the same for every later code from this installation.

deviceobject

platform, model, app_version, store, install_source, store_country, as the app reports them. Values may be null.

pro.from_customerboolean

The customer already pays for Pro themselves.

activationobject

{ live: false }, or { live: true, by_you, id, expires_at }. id and expires_at are present only when it is yours.

blocked_by_customerboolean

The customer removed your provider from this device.

eligibleobject

activate true or false, with reason when false (already_activated_by_you, device_has_live_activation, device_blocked_provider, platform_not_available) and requires_confirmation: true when the customer already has Pro.

Errors

404 device_not_found when the code is unknown or expired. 400 invalid_target when no code was sent.

Retrieve a device

GET/v1/devices/{device_ref}devices:read

The same preview, by the device_ref you saved. Use it to check a device before an extension or a new playlist, without asking the customer for a code.

Errors

404 device_not_found if the reference is not yours.

The activation object

An activation is AnyTV Pro on one device, paid with your credits, for a term you chose.

idstring

Save it next to your customer. You need it to extend, move, undo or revoke.

statusstring

reserved credits reserved, billing confirming (the 202 processing state). active the device has Pro. transferring and revoke_pending a move or a revoke in flight. expired the term ended. undone you undid it. revoked you ended it early. transferred it moved to a new device, see transferred_to. released the customer removed your provider. failed billing refused it; the credits were released.

device_refstring

The device it is on.

starts_at, expires_attimestamp or null

The term. Null while reserved.

external_refstring or null

Your own reference, 1 to 128 characters, set when you activated. You can list by it.

undo_deadlinetimestamp or null

Until when undo is possible: 72 hours after the activation committed. Null once closed.

confirmed_already_proboolean

You activated although the customer already had Pro.

transferred_from, transferred_tostring or null

The activation ids on either side of a move.

revoke_reasonstring or null

Why it ended early, when it did.

termsarray

Every term bought on this activation: kind (initial or extension), term, units, state, expires_at, committed_at.

created_at, updated_at, ended_attimestamp

ended_at is null while the activation is live.

Activate Pro

POST/v1/activationsactivations:write

Unlocks AnyTV Pro on the customer's device for the term, with your credits. Idempotency-Key required.

Body

codestring

The code on the TV. Send this or device_ref.

device_refstring

A reference you saved from a preview.

termstringrequired

P1Y or P2Y.

external_refstring

Your own reference for the customer, 1 to 128 characters. Not personal data.

confirm_already_proboolean

Send true to activate a device whose customer already pays for Pro. Without it that case answers 409 already_pro_confirmation_required.

Returns

201 with the activation, status active. 200 on a replay. 202 with { "status": "processing", "activation": … } when billing is slow: the activation is reserved and completes on its own; read it again in a minute.

Errors

StatuserrorWhat to do
400invalid_target, invalid_term, invalid_external_refFix the body.
402insufficient_creditsBuy credits in the console.
403provider_not_active, approval_required, kyc_required, not_allowlistedSee Your standing.
404device_not_foundThe code expired or the reference is not yours. Ask for a fresh code.
409already_activated_by_youExtend it instead.
409device_has_live_activationAnother provider activated this device.
409already_pro_confirmation_requiredResend with confirm_already_pro: true, or do not activate.
409device_blocked_providerThe customer removed your provider from this device.
409activation_failedBilling refused this attempt. Use a new Idempotency-Key to try again.
422platform_not_availableActivations are not offered on this device's platform or storefront.
429activation_cap_reachedToday's cap. Try tomorrow.
503activations_disabled, billing_unavailableRetry later with the same Idempotency-Key.

List activations

GET/v1/activationsactivations:read

Your activations, newest first.

Query parameters

statusstring

One status.

expiring_beforetimestamp

Only activations whose term ends before this. The way to find renewals due.

external_refstring

Your reference, exact match.

device_refstring

One device.

cursor, limitstring, integer

See Pagination.

Returns

An activations array and next_cursor.

Retrieve an activation

GET/v1/activations/{id}activations:read

One activation with its terms. Poll this, no more than once a minute, after a 202 processing.

Errors

404 activation_not_found if it is not yours.

Extend

POST/v1/activations/{id}/extendactivations:write

Adds a term to an active activation. The new term starts when the current one ends, so extending early loses nothing. Idempotency-Key required.

Body

termstringrequired

P1Y or P2Y.

Returns

200 with the activation and its new expires_at, or 202 processing.

Errors

404 activation_not_found, 409 activation_not_active, 409 extension_in_progress, 402 insufficient_credits, plus the standing errors.

Move to a new device

POST/v1/activations/{id}/transferactivations:write

The customer got a new TV. The remaining term moves to the new device as a new activation; the old one ends as transferred. Idempotency-Key required.

Two moves per activation chain in any 365 days are counted. A move is free when the old device is gone: the customer removed your provider there, the device was removed from their account, or it has not been seen for 30 days.

Body

code or device_refstringrequired

The new device.

keep_on_old_deviceboolean

Keep the playlists on the old device too. By default they are removed there and sent to the new device.

Returns

200 with the new activation and previous_activation_id, or 202 processing.

Errors

409 transfer_limit_reached with resets_at; 409 same_device; 409 activation_not_transferable; 409 device_has_live_activation when the new device belongs to another provider; the device and standing errors.

Undo

POST/v1/activations/{id}/undoactivations:write

A wrong code, a customer who changed their mind: within 72 hours of the activation committing, undo it and the credits come back as refunded_units. The customer's Pro ends. Idempotency-Key required. No body.

An activation that was moved cannot be undone, a device can be undone once, and a provider who undoes a large share of its activations over 30 days is asked to stop (409 undo_cap_reached).

Errors

409 undo_window_closed, 409 activation_transferred, 409 device_already_undone, 409 undo_cap_reached, 404 activation_not_found.

Revoke

POST/v1/activations/{id}/revokeactivations:write

Ends an activation early. The customer's Pro stops; no credits come back. Use undo within 72 hours instead when that applies. Idempotency-Key required. DELETE /v1/activations/{id} does the same.

Body

remove_deliveriesboolean

Also remove your playlists from the device. Default true. The answer carries removals_queued.

Errors

404 activation_not_found, 409 activation_not_active.

The delivery object

A delivery is one playlist you sent to one device. The device holds it; you see its state.

idstring

Save it to update or remove this playlist later.

sourcestring

provider for yours. (customer exists for playlists customers send themselves; you never see those.)

device_ref, activation_idstring or null

The device, and the activation it was sent for, if any.

type, name, hoststring

m3u or xtream; the name the customer sees; the playlist's host (and port). Credentials are never returned.

statusstring

pending waiting for the device. delivered the device has it. removal_pending and removed you removed it. removed_by_user the customer removed it; it is never sent again. superseded an update replaced it, see replaces_delivery_id on the new one. cancelled, expired, blocked it never reached the device. failed the device could not use it, see failure_class.

failure_classstring or null

auth the server refused the credentials, unreachable, parse, limit, unsupported, other.

last_ack, last_ack_atstring, timestamp or null

The device's last word about it, for example applied.

required_capabilityinteger

The app capability the payload needs. A device on an older app leaves it pending until it updates.

created_at, delivered_at, removed_at, updated_attimestamp

Send a playlist

POST/v1/deliveriesdeliveries:write

Sends a playlist to a device. Free, no activation needed. The app adds it on its next check in. Sending a second playlist with the same host and name updates the first in place.

Body

code or device_refstringrequired

The device.

playlistobjectrequired

For M3U: { "type": "m3u", "url": "https://…" }. For Xtream: { "type": "xtream", "server": "http://host:port", "username", "password" }. Both accept epgUrl. URLs are http or https, up to 2048 characters, without credentials inside the URL; username and password up to 128 characters with no spaces; the whole playlist under 4 KB.

namestringrequired

Shown to the customer in the app, 1 to 120 characters.

profile_hintstring

Up to 60 characters. The app may use it to pick a profile.

Returns

201 with the delivery, status pending.

Errors

StatuserrorMeaning
400invalid_target, invalid_playlist, invalid_nameFix the body. The message says what.
403provider_not_active, approval_requiredSee Your standing.
404device_not_foundThe code expired or the reference is not yours.
409device_blocked_providerThe customer removed your provider from this device.
409playlist_limit_reachedThe device holds the most playlists your account may deliver. Remove one first.
409host_on_holdThis host is on hold after a rights holder's notice. Contact AnyTV.
429new_device_cap_reachedToday's new device cap. Try tomorrow.
503deliveries_disabled, billing_unavailableRetry later.

Send for an activation

POST/v1/activations/{id}/deliveriesdeliveries:write

The same as Send a playlist, addressed by an active activation of yours instead of a device. The delivery is linked to the activation: it moves with a transfer and goes with a revoke.

Body

playlist, name, profile_hint as above. No code or device_ref.

Errors

404 activation_not_found, 409 activation_not_active, and the send errors.

Update a playlist

PUT/v1/deliveries/{id}deliveries:write

Changes a live playlist in place: a new password, a new server, a new name. The device replaces the old entry without the customer doing anything. The answer is the new delivery, with replaces_delivery_id pointing at the old one, which becomes superseded.

Body

playlistobject

Only the fields that change, same shape as on send. The type cannot change: remove and send a new one instead.

namestring

1 to 120 characters.

epg_urlstring or null

Set, or null to clear.

Errors

404 delivery_not_found, 409 delivery_not_live, 409 replacement_pending (the previous update has not reached the device yet), 409 type_change_needs_remove_and_add, 400 invalid_playlist, 400 invalid_name.

Remove a playlist

DELETE/v1/deliveries/{id}deliveries:write

Takes the playlist off the device. A pending one is cancelled; a delivered one becomes removal_pending and the app removes it on its next check in. Works in every account state.

Removal is real here. Unlike a playlist the customer typed themselves, a delivered playlist is removed from the app when you remove it. Still, the customer may have written the details down: your own server decides whether a line works.

Errors

404 delivery_not_found, 409 already_removed. On a lost response, already_removed means the first attempt worked.

Move playlists to a new host

POST/v1/deliveries/bulk-host-updatedeliveries:write

Your server moved. Every live playlist of yours that points at the old host gets an update pointing at the new one, 50 at a time. Preview first with dry_run: true and send the count back as expected_count; a count that changed in between is refused, so you never move more than you looked at.

Body

from_host, to_hoststringrequired

Host names, with the port when the playlists use one. No scheme, no path.

dry_runboolean

true only counts.

expected_countinteger

The count from the dry run. Required when dry_run is false.

Returns

{ matched, updated, skipped, remaining }. 200 for a dry run or when nothing moved, 202 when updates were queued. With remaining above zero, run the dry run again a minute later for the next chunk; moved playlists no longer match.

Errors

400 invalid_from_host, 400 invalid_to_host, 400 same_host, 404 nothing_matched, 409 count_mismatch, 429 rate_limited (one a minute).

List playlists

GET/v1/deliveriesdeliveries:read

Query parameters

device_refstring

One device.

statusstring

One status.

cursor, limitstring, integer

See Pagination.

Returns

A deliveries array and next_cursor.

Retrieve a playlist

GET/v1/deliveries/{id}deliveries:read

One delivery. To wait for delivered, check again no more than once a minute. There are no webhooks yet.

Errors

404 delivery_not_found.

Check your key

GET/v1/me

Which provider and key you are using, the key's scopes and expiry, your caps, and your capabilities right now. It needs no scope, so it is the right first call when you set up, and a good health check for monitoring.

Credit balance

GET/v1/creditscredits:read

available_units you can spend now, reserved_units held by activations still confirming, credit_limit_units a credit line AnyTV may have granted, and available_credits as text.

Credit ledger

GET/v1/credits/ledgercredits:read

Every move of your credits, newest first, paged. Each entry has a kind: purchase, reserve, commit, release, refund_undo, adjustment, forfeit, purchase_refund, transfer_in, transfer_out; units and reserved_units as signed deltas; and the activation_id or purchase_id it belongs to.

Subscription lifecycle

What to call when something happens in your billing system.

EventWhat to do
New customer paysPreview the code, activate if they bought Pro, send the playlist (or send for the activation). Save device_ref, the activation id and the delivery id.
Customer renewsExtend the activation. The new term starts when the old one ends.
Renewals dueList with expiring_before set a month out.
Line password or server changesUpdate the playlist. One server for everyone? Move playlists to a new host.
Wrong device, within 72 hoursUndo. Credits come back.
Subscription endsLet the activation expire, or revoke it early (no credits back). Disable the line on your own server too: that is what stops playback for a playlist the customer wrote down.
Customer gets a new TVMove the activation; the playlists move with it.
Customer removed you on their TVThe activation shows released and calls answer device_blocked_provider. Nothing to do until they allow you again. A move to a new device of theirs is free.

Go live checklist

  • The key is stored in a secrets manager or environment variable, not in code.
  • The key has only the scopes your system uses.
  • Every activation write sends an Idempotency-Key built from your own order or operation number.
  • Requests have a timeout, 20 seconds is a good value.
  • Network failures, 5xx, 409 request_in_progress and short 429 waits are retried with growing waits. Daily caps and other 4xx are not, and 401 alerts a person.
  • 202 processing is handled: you read the activation again later instead of activating twice.
  • The key, the Authorization header and customer playlist passwords never appear in your logs.
  • You store device_ref, activation ids and delivery ids with each customer.
  • device_not_found leads to a message for the customer, not to a retry loop.
  • Your code branches on error, never on message, and ignores response fields it does not know.
  • Someone on your team knows where to revoke a key, and reads the audit trail now and then.

Versioning and changes

This is version 1, under /v1.

  • We may add new endpoints, new optional request fields, new response fields, new statuses and new error codes. Build your code to ignore what it does not know.
  • We will not remove or rename fields, change their types, or change the meaning of an error code inside v1.
  • A change that would break you gets a new version, and v1 keeps working alongside it.

Changelog

DateChange
2026-10-11First release of v1: device preview, activations with extend, move, undo and revoke, playlists with update, removal and bulk host move, credits, safe retries.

A machine readable description of the API is available as an OpenAPI file. You can import it into Postman or Insomnia to try every call.