If your website already knows who your members are, it can unlock their television directly. Your viewer signs in where they always sign in, confirms the code on their screen, and the TV opens. They never type an access code, and their identity stays on your side.
This is for organizations that want to keep subscriptions, customer data and billing outside their app vendor. If you would rather not integrate anything, access codes do the same job with no engineering at all.
This API is in beta. It is live and you can build against it today. Two things follow from beta: the apps that enforce locking are still rolling out, and the contract itself can still move if it does not fit you. Both are covered below.
What crosses the boundary
Deliberately thin, in both directions.
We receive | We do not receive |
A code that is on a television right now | Who the viewer is |
An opaque reference you choose for that viewer | What they paid, or whether they did |
An optional list of tags | Their email, name or address |
What we store is a device, a token hash and those tags. The reference is yours and means nothing to us: your-user-8842, a UUID, a hash. Pick something you can look up on your side and that does not leak anything on ours. It appears in a URL path, so keep it opaque and under 255 characters.
The flow
The television asks us for a link and shows the short code it gets back.
Your viewer, signed in on your site, enters that code on a page you host.
Your server calls
POST /api/partner/claimwith the code and your reference for that viewer.The television picks it up on its next poll, within about three seconds.
Your page replaces the Tappla activation page. You never see the television's secret, and the television never sees your user.
Which apps this works on
The API is the same on every platform. What differs is whether the app on the television acts on the lock, because that is enforced by the app rather than by us.
Platform | Where it stands |
Fire TV | Enforces locking and completes the handshake in the current app. |
Roku | Arrives with the new SDK app, which we are rolling out now. |
Apple TV | Arrives with the new SDK app, which we are rolling out now. |
Until an app is rebuilt on the new SDK, a locked row still shows and still plays there. Nothing you build against this API has to change when that happens; it is a rebuild on our side, not a new contract. Ask [email protected] where your apps stand before you rely on the lock in production.
Authentication
Authorization: Bearer tpk_...
One key per integration, hashed at rest, shown once when it is created. The key identifies your application by itself, which is why no endpoint takes an app id. Ask us at [email protected] for a key and give it a label, so that two live keys are still tellable apart when you rotate. Rotation is mint-then-revoke.
A missing header, a malformed one, a revoked key and a lapsed subscription all return the same 401 with the same body.
Treat the key like any other server credential: keep it on your backend, never in a browser or a mobile app, and tell us at [email protected] if one is exposed so we can revoke it. A key can only ever touch your own account.
POST /api/partner/claim
Attaches the television showing code to a viewer you have already authenticated.
{
"code": "K7M2QP",
"subjectRef": "your-user-8842",
"tags": ["premium"],
"expiresAt": "2026-09-18T00:00:00Z",
"maxDevices": 3
}
Only code is required. No tags is a complete one-tier grant: locked content with no required tags plays on any linked device. No expiresAt means it does not expire, which is the shape of a subscription tier; a rental is the case that has to say so. No maxDevices means unlimited.
A successful call returns the entitlement as it now stands:
{
"status": "claimed",
"subjectRef": "your-user-8842",
"tags": ["premium"],
"active": true,
"expiresAt": null,
"maxDevices": 3,
"devices": 1
}
Idempotent on subjectRef. Calling again for the same viewer adds their second television, updates tags after an upgrade, or pushes the expiry out after a renewal. It does not create a second entitlement, which would make a later revoke look like it worked while the other one kept playing. Calling after a revoke lets the viewer back in and keeps the televisions already attached.
Every call states the entitlement in full, so an omitted field is cleared rather than kept. Send tags again when you add a second television, or that viewer ends up with none. It works this way because you derive all of it from your own subscription record on every call; the other rule would mean a downgrade that forgot to send tags quietly left someone on the tier they stopped paying for. Changes reach every television on that entitlement at its next poll.
You may omit subjectRef if you will not name the viewer even opaquely. That grants a fresh entitlement each time and leaves a later revoke nothing to aim at, which is the trade rather than a bug.
Limits. subjectRef and each tag are 255 characters at most, and an entitlement holds at most 50 tags. Anything past that is a 422 naming the field.
Status | Meaning |
| Linked. The television picks it up within about three seconds. |
| No pending code of that value in your account. A code belonging to someone else returns this too. |
| The code was real and the viewer was too slow. Tell them to read the fresh code off the screen, which is a different instruction from "that never existed". |
|
|
|
|
GET /api/partner/entitlements/:subjectRef
What this viewer holds, including how many televisions are on it. 404 not_found if unknown, including when the reference belongs to another account.
DELETE /api/partner/entitlements/:subjectRef
Switches the viewer off. Takes effect at the next poll and the next launch, on every television they linked. 404 not_found if unknown.
Why you push to us rather than us calling you
The obvious request is the other one, so it is worth saying why it is this way round.
If we called your API on every playback check, a viewer would lose their television whenever you had an outage, and your service would sit in the path of every launch of every app. Instead, entitlements are re-read on every poll and every launch rather than trusted from claim time, so a revoke propagates on its own the moment it reaches us. Nothing to notify, nothing to touch on the hardware.
The trade: revocation is as fresh as your last call to us, not as fresh as your own database. For a lapsed subscription that gap is a webhook away. If you need per-play authorisation against live state, this shape is the wrong one and we should talk before you build against it.
Tags and tiers
An item in your feed can carry required tags, a device holds tags, and the app matches the two. Tags rather than item ids, so the check stays the same size as your catalog grows and you never have to know what is in the feed today.
Locked content with no required tags plays on any linked device. That is the one-tier model, "you need an account, any account", and it is what the dashboard produces on its own. Multiple tiers are available here through the API.
Current limits
Keys are issued by us, not from the dashboard. Ask support and we will mint one.
No webhook from us to you. Nothing tells your system that a television linked. Poll the entitlements endpoint if you need to know.
No bulk endpoint. One viewer per call. If you need to migrate many at once, talk to us rather than looping.
Roku and Apple TV enforcement is still rolling out. See Which apps this works on above.
The contract is young and no customer is locked into it yet, so if something about it does not fit how your system works, that is worth a conversation rather than a workaround. Write to [email protected].
Related
Members-only content — the dashboard side: locking playlists and handing out access codes
How to write your own video content feed — including how to mark items as members only in your own feed