Back

Blog details

AIOZ Stream Node.js SDK: A Complete Getting Started Guide

AIOZ Network
6 min readAugust 07, 2026
aioz-streamguidedeveloper-apis
AIOZ Stream: peer-to-peer streaming replaces the CDN bill

Most video API clients leave chunked uploads, pagination, and token refresh as homework for whoever integrates them. AIOZ Stream's Node.js client does that work itself. This is a walk through installing it, creating and uploading a video, the CRUD operations you'll reach for right after, and the handful of things worth knowing once you're past the first request.

TL;DR:

  • Install with npm install @aiozstream/nodejs-client, then construct a client with your public and secret key.
  • Uploading is either one call (client.uploadVideo()) or three explicit ones (video.create(), video.uploadPart(), video.uploadVideoComplete()) depending on how much control you want.
  • Full CRUD is there too: getDetail(), getVideoPlayerInfo(), getVideoList(), update(), and delete().
  • Chunking, pagination, and token refresh are handled by the SDK, not something you write yourself.
  • Rate-limit headers are available through listWithResponseHeaders() variants of list methods, if you need to read them directly.

Install and set up the client

Install the package with npm or yarn:

npm install @aiozstream/nodejs-client
# or
yarn add @aiozstream/nodejs-client

Then construct a client with the public and secret key from an API key you've generated in the dashboard:

const client = new StreamClient({
  publicKey: 'YOUR_PUBLIC_KEY',
  secretKey: 'YOUR_SECRET_KEY'
})
Code on a screen representing an SDK client handling upload and pagination logic for a developer

Creating and uploading a video

Creating a video object comes first, and it doesn't need a file yet, just metadata:

const videoCreationPayload = {
  title: 'First video',
  description: 'A new video.'
}
const video = await client.video.create(videoCreationPayload)

From there you have two paths. The explicit, three-call version uploads the file and then confirms completion separately:

const uploadResult = await client.video.uploadPart(
  video.data.id,
  './path/to/video.mp4'
)
const checkResult = await client.video.uploadVideoComplete(video.data.id)

Or skip straight to a single call that does both steps for you:

await client.uploadVideo(video.data.id, './path/to/video.mp4')

The three-call version is worth keeping around if you want to do something between the upload finishing and marking it complete, like logging progress or triggering a separate process. Otherwise, the single-call version is less code for the same result.

Retrieving, listing, updating, and deleting videos

Upload is only one corner of what the client does. The rest of the video lifecycle is a small, predictable set of calls:

  • client.video.getDetail(id), which maps to GET /videos/{id}, for fetching a single video's current state.
  • client.video.getVideoPlayerInfo(id), which maps to GET /videos/{id}/player.json, for the data a player needs to embed and play it back.
  • client.video.getVideoList(), which maps to POST /videos, for listing and searching videos on the account.
  • client.video.update(id, payload), which maps to PATCH /videos/{id}, for changing title, description, or other metadata after the fact.
  • client.video.delete(id), which maps to DELETE /videos/{id}.

None of these need a different client or a different credential; they're the same video sub-client the upload calls live on. The pagination handling mentioned in the SDK's own description shows up specifically in getVideoList(): rather than manually tracking page tokens or offset parameters across repeated calls the way you'd need to against the raw REST endpoint, the client manages that state internally, so paging through a large video library reads as a normal loop over results instead of hand-rolled cursor bookkeeping.

What the SDK handles for you

AIOZ Stream's own SDK documentation is specific about this: "chunking files is handled for you, as is pagination and refreshing your tokens." That's the actual value of using the SDK over calling the REST API directly. Uploading a large file as one request isn't reliable; a dropped connection partway through a single-request upload of a multi-gigabyte file means starting over from byte zero, which is exactly the failure mode chunked, resumable upload protocols like tus exist to solve industry-wide, not just for AIOZ Stream specifically. Splitting the file into parts and reassembling them is the kind of logic that's easy to get subtly wrong the first time you write it yourself, and here it's already done.

Handling errors

The SDK's own documentation shows error handling as a plain try/catch around an async call:

try {
  const video = await client.video.create(videoCreationPayload)
} catch (e) {
  console.error(e)
}

There's no special error type or wrapper to learn beyond that. A failed call throws, and whatever the underlying REST API returned as an error is what you'll see in the caught exception. Worth building in from the start: a 429 (rate limit) or a 5xx server error is generally worth retrying with backoff, while a 4xx validation error on something like video.create() almost never resolves itself on retry, since the request itself is what's wrong, not a transient condition. Treating every caught error the same way, retry blindly or fail immediately, works until it doesn't; distinguishing those two categories early avoids either hammering a rate limit or giving up on something a short delay would have fixed. A minimal version of that split looks like checking the caught error's status before deciding what to do next, rather than wrapping every call in the same blanket retry loop regardless of what actually failed:

try {
  await client.video.create(videoCreationPayload)
} catch (e) {
  if (e.status === 429 || e.status >= 500) {
    // back off and retry
  } else {
    // log and surface the error, retrying won't help
  }
}

That's a small amount of extra code for a meaningfully more resilient integration than either extreme.

Reading rate limit headers

List methods return just the response body by default, but a listWithResponseHeaders() variant of the same method returns both. The documented example calls it on the webhook client specifically:

const { headers, body } = await client.webhook.listWithResponseHeaders()

That gives you X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Retry-After alongside the actual data. Most integrations won't need this on day one, but it's there once you're running enough volume to actually care about backing off correctly instead of guessing.

A full example: upload plus webhook instead of polling

Putting the pieces together, a common real pattern is registering a webhook once instead of polling getDetail() in a loop after every upload:

const webhook = await client.webhook.create({
  url: 'https://your-app.example.com/webhooks/aioz',
  events: ['encoding_finished', 'encoding_failed']
})

const video = await client.video.create(videoCreationPayload)
await client.uploadVideo(video.data.id, './path/to/video.mp4')
// Your webhook endpoint gets called when encoding actually finishes,
// instead of your code checking getDetail() on a timer.

The webhook endpoint itself is just a normal route in whatever server framework you're using, not something the SDK generates for you, and it should treat delivery as at-least-once rather than assuming an event only arrives a single time. That's the same idempotency point covered in more depth in the Developer Guide's webhook section, worth applying here rather than treating this SDK's webhooks as a special case.

Beyond video upload: the other sub-clients

The same client exposes players, playlist, webhook, and analytics alongside video, all built from the same public/secret key pair. None of them need a separate credential or a separate client instance; if you're already authenticated to upload video, you're already authenticated to manage a playlist or register a webhook.

Frequently Asked Questions

Do I need to handle chunked upload myself for large files?
No. uploadPart() handles chunking for you, and uploadVideo() wraps both the upload and completion check into a single call if you don't need to do anything in between.

What's the difference between video.create() and uploadVideoComplete()?
create() registers a video object with metadata before any file exists. uploadVideoComplete() confirms the file upload is finished so transcoding can start.

How do I fetch a list of videos instead of one at a time?
client.video.getVideoList(), which maps to POST /videos under the hood, since a list call typically needs a filter or search payload.

Does the SDK handle API key expiration or token refresh automatically?
Yes, per AIOZ Stream's own SDK documentation, token refresh is handled by the client rather than something you implement yourself.

How do I check if I'm close to hitting a rate limit?
Use the listWithResponseHeaders() version of a list method instead of the default one; it returns the response body plus the rate-limit headers.

Should I retry every failed SDK call the same way?
No. A rate-limit (429) or server error (5xx) is usually worth retrying with backoff. A validation error (4xx) on a call like video.create() means the request itself needs fixing, not a delay, so retrying it unchanged will just fail again.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

What Is QoE in Video Streaming, and Why It Matters

QoE is not QoS. Here is how Quality of Experience is actually measured, what research says hurts viewers most, and how AIOZ Stream tracks and targets it.

aioz-streamguide
6 min readAugust 24, 2026
blog thumbnail

How On-Chain Wallet Top-Ups and Token Billing Work

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

aioz-streamguide
6 min readAugust 23, 2026
blog thumbnail

Glass-to-Glass Latency Explained: What It Actually Means

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.

aioz-streamguide
7 min readAugust 22, 2026
blog thumbnail

AIOZ Stream Pricing: Storage, Delivery, Transcoding

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

aioz-streamguide
7 min readAugust 21, 2026
blog thumbnail

What Is Low-Latency HLS (LL-HLS) and When to Use It

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.

aioz-streamguide
7 min readAugust 20, 2026
blog thumbnail

AIOZ Stream Video Player: Features and Customization Guide

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.

aioz-streamguide
6 min readAugust 19, 2026