CDN
CDN
Oblien's CDN stores and delivers your assets (images and files), generating image variants on demand and serving them from your account's edge host — optionally on your own domain.
In one line — your backend mints a short-lived upload permit, your client uploads straight to your account's CDN host with it, and the CDN records the upload back to Oblien. Files serve from your account host; namespace is an API-side tag for quota, sorting and listing. New here? Read How it works first.
At a glance
| Capability | Summary |
|---|---|
| Per-account host | Your account serves from one <slug>.cdn.oblien.com (or a custom domain), shared across all your namespaces. See How it works. |
| Namespaces | An API-side tag on each upload — organize, filter, and quota. Not a host, never in a URL. |
| Uploads | Client uploads with a one-shot permit; CDN returns URLs + a recorded confirmation. See Uploads. |
| Variants | Thumbnails/resizes/re-encodes chosen per request via the permit's variants object — no server presets, default none. |
| Custom domains | Serve from cdn.yourbrand.com (account-level) via the /cdn/domains API (DNS + auto TLS). See Custom domains. |
| Quotas | Per-namespace storage + monthly-ingest caps, enforced at token mint. See Quotas. |
| Auto-delete | Mark an upload to expire after a TTL; the node reclaims it. See Auto-delete. |
| Traffic & suspend | Delivery egress is metered and billed per account; over-limit accounts are suspended. See Traffic & billing. |
| Usage & stats | Per-namespace usage, windowed series, quotas and files. See Usage & stats. |
Quick start
import Oblien from 'oblien';
import { readFileSync } from 'node:fs';
const oblien = new Oblien({
clientId: process.env.OBLIEN_CLIENT_ID!,
clientSecret: process.env.OBLIEN_CLIENT_SECRET!,
});
// Server-side one-shot: mints a permit + uploads, scoped to a namespace.
const { url, variants } = await oblien.cdn.upload(
{ data: readFileSync('./logo.png'), filename: 'logo.png', contentType: 'image/png' },
{ namespace: 'customer-123' },
);
// url → https://<slug>.cdn.oblien.com/static/ab/cd/logo.png# 1. Backend mints a permit (scoped to a namespace)
POST /cdn/token
X-Client-ID: <id>
X-Client-Secret: <secret>
{ "namespace": "customer-123" }
# → { "token": "<permit>", ... }
# 2. Client uploads to your account host with the permit
POST https://<slug>.cdn.oblien.com/api
Authorization: Bearer <permit>
Content-Type: multipart/form-data (field: "file")
# → { "url": "https://<slug>.cdn.oblien.com/static/…", "variants": [...], "recorded": true }# 1. Backend mints a permit
TOKEN=$(curl -s -X POST https://api.oblien.com/cdn/token \
-H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
-H "Content-Type: application/json" -d '{"namespace":"customer-123"}' | jq -r .token)
# 2. Client uploads with the permit (host from the mint/your backend)
curl -X POST "https://$CDN_HOST/api" \
-H "Authorization: Bearer $TOKEN" -F "file=@./logo.png"Read How it works for the account-host + namespace-tag model and the
backend-vs-client split, then the upload contract for
request/response shapes, per-request variants, and single-use permit semantics.