On this page
TL;DR — Your API keys live on your servers only. The viewer's device is untrusted: it only ever holds a ticket for one episode on that device, for 30 minutes. Revoke a key the moment you think it leaked, then tell Wandura. Never put keys, tickets or signed links in apps, front-end code, logs, analytics, crash reports or URLs.
viewer_refis an opaque, hashed id, kept by Wandura for 90 days.
Trust boundary
| Zone | Holds | Must never hold |
|---|---|---|
| Viewer device | One ticket per episode, in memory; the Player SDK licence file | API keys |
| Your backend | API keys, your paywall, your viewers | — |
| Wandura | Your licences, the films, the ticket ledger | Your viewers' identities |
Your ticket endpoint is the gate. Wandura checks your licence, not your viewers. Device values come from a client you do not control. So your endpoint must:
- require a signed-in viewer session (or your own device attestation) before it asks Wandura for a ticket;
- apply your paywall before every ticket request;
- limit tickets per viewer and per device (for example 10 per minute) and alert on viewers who open many films in a short time;
- treat
union_infoanddrm_kekas untrusted input: pass them through, never use them for anything else.
Wandura's rate limit is per organisation: one abusive client of your app can use up the allowance of all your viewers. See Rate limits.
Keys
Scopes and least privilege
One key per system and per environment, with only the scopes that system needs. The scope of each endpoint is on Authentication. A catalog sync job never needs playback; a marketing job needs only creatives:export.
Production and testing
There is no separate staging host: every key calls https://www.wandura.ai. What keeps test traffic apart is the organisation.
Each partner gets a test organisation next to its real one. Its keys call the same production URL exactly like real keys, against sample films only, and its plays are never counted as views, usage or revenue. It also accepts the Wandura-Simulate header to reproduce errors on demand; production keys ignore that header completely. See Testing.
Never use a production key in a test environment, or the other way round.
Storage
- Keep keys in a secrets manager, exposed to the one service that needs them as
WANDURA_API_KEY. - Never commit a key. Add the pattern
wnd_live_[A-Za-z0-9_-]{32}to your secret scanner and to pre-commit hooks. - Search every app build for
wnd_live_before release: there must be no match.
Key lifecycle
| Action | Who | What happens |
|---|---|---|
| Create | Admin or Developer, on Developers | The full key is shown once. A new key is pinned to the latest dated API version. |
| Rotate | Admin or Developer | Replaces the secret, keeps label, scopes and version pin. The old secret is refused within about 1 second on every Wandura server (always within 30 seconds) — there is no overlap. |
| Revoke | Admin or Developer | Final. New requests with the key are refused within about 1 second (always within 30 seconds). |
| Already-issued tickets | — | Keep playing until they expire (≤ 30 minutes). They cannot be recalled. |
Rotate without downtime: create a second key with the same scopes, deploy it, check traffic has moved (Last used on the old key stops changing), then revoke the old one. A new key is pinned to the latest dated version: if your key is pinned to an older one, send Wandura-Version: <your date> with the new key, or read api.pinned_version from GET /config with both keys before you switch. See Migrating versions.
Wandura monitors new and rotated playback keys and organisations that reach their playback limit. You still own your keys: watch Last used and API usage, and tell Wandura at once if you suspect a leak.
Every key creation, rotation and revocation is recorded in Wandura's audit log with your organisation, the member who did it and the key prefix.
If a key leaks
- Revoke it on Developers (any Admin or Developer). New requests stop within about a second.
- Deploy a replacement with the same scopes. Mind the version pin (above).
- Tell Wandura in your team's Wandura Discord channel: the key prefix, when and where it was exposed. Wandura can list the tickets issued with it (kept 90 days) and, if tickets already issued must stop before they expire, suspend the affected films for your organisation.
- Check Developers → API usage for calls you did not make.
- Close the leak path: repository, app binary, logs, crash reports, CI output. Add the secret-scanner pattern.
Calling http:// instead of https:// sends the key unencrypted before the redirect: treat that key as leaked.
Tickets and signed links
| Value | Rule |
|---|---|
play_auth_token |
A bearer secret for one episode on one device, valid ≤ 30 minutes. Keep it in memory for the current play. Never write it to disk, logs, analytics or crash reports. |
manifest_url |
A bearer link: anyone holding it can download the stream until expires_at (≤ 15 minutes). Same rules as the token. |
| Open video links | Anyone holding one can play or download the file until it expires (1 hour). Do not publish them, do not store them in the app. |
| Subtitle URLs | Public and long-lived. Fine to cache; do not publish lists of them. |
A leaked token or link expires on its own; stop the path that leaked it.
Viewer and device data
viewer_refis optional, opaque, at most 256 characters. Wandura stores it with each ticket for 90 days, for support lookups, then keeps only monthly counts. Never put an email address, phone number or name in it. Use a keyed hash:HMAC(secret, user_id)plus a hash of your install id, so it means nothing outside your systems and stays stable per viewer and device. The examples do exactly this.union_infois a persistent device identifier generated by the Player SDK: personal data on your side. Wandura uses the device values only to bind the ticket and does not store them. Do not log them raw; hash them if you need them for debugging.
Never put secrets here
| Value | App / front-end JS | Server logs, APM, proxies | Analytics | Crash reports | URLs | Support chats |
|---|---|---|---|---|---|---|
| API key | never | never (redact Authorization) |
never | never | never | prefix only |
play_auth_token, manifest_url |
memory only, current play | never | never | never | never | never |
union_info, drm_kek |
generated there | hashed only | never | avoid | never | if asked |
viewer_ref |
— | yes | pseudonymous only | yes | avoid | yes |
The safe-logging helper in the examples drops these fields for you: Observability.
Transport
- Always
https://www.wandura.ai. TLS 1.2 or 1.3 only. - Not
wandura.aiwithoutwww: it redirects, and some clients drop the body of aPOSTon a redirect. - The API does not use cookies for authentication and sends no CORS headers: browser calls fail by design.
- Never put a key in a query string. The API only reads the
Authorizationheader.
Related
- Authentication: sending the key, scopes.
- Go-live checklist: the security items to tick before release.
- Canonical API behaviour: every timing on one page.
Updated 5 Oct 2026 · Change history (2)