
Handing a CMS integration or a third-party contributor the same API key you use for your own account means giving them the power to delete every video on it, whether they need that or not. AIOZ Stream's API keys come in two roles specifically to avoid that: one that can do everything, and one that can only upload. This is what each one actually allows, how to create and manage keys, and the security practices worth following once you have more than one key in play.
TL;DR:
full_access ("all the actions with the api key") and only_upload ("only upload video to AIOZ Stream").The documentation describes full_access as covering "all the actions with the api key" and only_upload as restricted to "only upload video to AIOZ Stream." That's a narrow, specific boundary: an upload-only key can add video content but can't touch account settings, existing content, or other API keys, including keys it might otherwise be tempted to create for itself. Full-access can do all of that, including creating and revoking other keys, which is exactly why it shouldn't be the default choice for anything you're handing to an external system.
A key is created with a name, a TTL in seconds, and a type:
POST /api/api_keys
{
"api_key_name": "cms-integration",
"ttl": "2592000",
"type": "only_upload"
}The response includes the key's public identifier, a secret, and a truncated version of that secret:
{
"status": "success",
"data": {
"api_key": {
"id": "...",
"name": "cms-integration",
"public_key": "...",
"secret": "...",
"truncated_secret": "...",
"type": "only_upload",
"expired_at": "..."
}
}
}The full secret is only ever shown in this response. After that, the API only returns the truncated version, which is enough to recognize a key in a list but not enough to authenticate with. If it's lost after creation, the only fix is deleting the key and creating a new one, not recovering the old secret.
Beyond creation, the API supports listing keys with search, offset/limit pagination, and sorting by name or creation date; renaming a key with a PATCH request (the only field you can update after creation is its name, not its role or TTL); and deleting a key outright, which revokes it immediately. One detail worth double-checking in your own account rather than assuming: the documented create endpoint is on aiozstream.network, while list, update, and delete are documented on api.aiozstream.network, a different subdomain. Verify which host your actual requests need to hit rather than assuming both operations share one base URL. This is a small thing to get wrong that produces a confusing failure mode: a request to the wrong host for a given operation typically fails with a generic connection or routing error rather than a clear "wrong endpoint" message, which can send debugging effort toward the credential or payload when the actual problem is just the base URL.
Requests can carry either a bearer token or a pair of dedicated headers, stream-public-key and stream-secret-key. Both are documented as valid; which one you reach for is mostly a question of what's more convenient for the client you're building, a bearer token if you're already handling OAuth-style tokens elsewhere, the dedicated headers if you'd rather keep the public/secret key pair explicit in your request code.
None of this is generic advice invented for this article; it's what AIOZ Stream's own documentation tells you to do. On scope: "always use the most restrictive role necessary for a given use case." On expiration: "for API keys used in temporary contexts, always set an expiration date," rather than leaving the TTL at its maximum by default. On rotation: "periodically regenerate and replace API keys to reduce the risk of unauthorized access." On storage: "never expose your secret tokens in client-side code or publicly accessible environments." That last one isn't a theoretical risk. Automated scanners actively crawl public GitHub repositories and client-side JavaScript bundles specifically looking for exposed credentials, which is exactly why GitHub runs its own secret scanning against pushed code by default: a key committed to a public repo or shipped in browser-side JS isn't a hypothetical leak, it's typically found within minutes by something other than the person who put it there. None of these are unusual for API security in general; broken object-level and broken function-level authorization, exactly the failure mode a scoped, least-privilege key is meant to prevent, sit at the top of the OWASP API Security Top 10, the industry's most widely referenced list of API-specific security risks. They're worth following specifically here because a leaked full_access key on this platform can create and revoke other keys, not just touch video content, which is a broader blast radius than a typical scoped credential leak.
Say a CMS plugin needs to upload video on behalf of your account without you handing over full control. The right shape is an only_upload key, named for what it's actually for so it's identifiable in a list later, with a TTL matched to how long that integration is expected to run rather than the maximum available. If the integration is replaced or the contract ends, deleting that one key revokes exactly that access, without touching any other key or requiring you to rotate credentials across unrelated systems. That's the actual payoff of the two-role split: the blast radius of a compromised or simply retired key stays scoped to what it was created for.
Because a key's secret can only be viewed once, at creation, rotation has to be a create-then-delete sequence rather than a single "regenerate" action on the existing key. Create the new key first, with the same role and a name that makes the swap obvious in a list later, deploy the new credential to whatever's using it, confirm it's actually working, and only then delete the old one. Deleting the old key before confirming the new one works is the mistake worth avoiding here, since a revoked key fails immediately and silently from the calling system's perspective, and there's no way to temporarily un-revoke it to buy time while debugging. A short overlap window where both keys are valid costs nothing and removes the failure mode entirely.
Can I see a key's secret again after creating it?
No. The full secret is only returned once, at creation. After that, only a truncated version is shown; if the secret is lost, delete the key and create a new one.
What's the practical difference between full_access and only_upload?
Full_access covers every action, including managing other API keys. Only_upload is restricted specifically to uploading video and can't touch account settings, existing content, or other keys.
Can I change a key's role after creating it?
No. The update endpoint only supports renaming a key. Changing its role means creating a new key with the correct type and deleting the old one.
What's the maximum TTL for a key?
The documented maximum is 2147483647 seconds, roughly 68 years. AIOZ Stream's own guidance is to set a real expiration for temporary use cases rather than defaulting to the maximum.
How do I rotate a key without breaking whatever's using it?
Create the new key first, deploy and confirm it works, then delete the old one. Deleting before confirming the replacement works means a revoked key can fail an integration immediately with no way to temporarily restore it.
Do I have to use a bearer token, or can I use the public/secret key headers instead?
Either is supported. Bearer tokens and the stream-public-key/stream-secret-key header pair are both documented, valid ways to authenticate.
Is it really risky to put a secret key in client-side JavaScript?
Yes, and not just in theory. Automated scanners routinely crawl public repositories and shipped browser JS specifically hunting for exposed credentials, which is why services like GitHub run always-on secret scanning by default. Treat any secret key that reaches a browser as compromised.

How AIOZ Stream wallet billing actually works: token deposits, conversion rates, why the network matters, and the volatility risk fiat billing never has.

Glass-to-glass latency is camera-to-screen delay, the only number that matches what viewers feel. Here is what causes it, and how to measure it yourself.

A complete guide to how AIOZ Stream pricing actually works: the three cost components, hourly wallet billing, and where decentralized delivery beats AWS.

Low-Latency HLS cuts glass-to-glass delay from 30 seconds to about 2 to 5 seconds. Here is how LL-HLS actually works, what it costs, and when to use it.

A complete guide to the AIOZ Stream video player: what it does out of the box, two different paths to customizing it, and what still requires the API.

How to white-label the AIOZ Stream video player via the Player Theme API: creating a theme, uploading a logo, and every controllable field it supports.