CDN

Quotas & usage

Each namespace can have two optional CDN storage caps, both in bytes:

  • cdn_max_bytes — total active-storage cap (how much it may have stored at once).
  • cdn_monthly_bytes — per-calendar-month ingest cap (how much it may upload in a month; resets on the 1st).

A namespace with no cap of its own inherits the account default; with neither, it's unlimited. Both count the full footprint — the original plus every generated variant (each variant is a real file). Delivery traffic is a separate axis — see Traffic & billing.

Per-namespace overrides

Namespaces are free tags — you don't pre-create them; you just pass namespace when minting a token (see Uploads). Most need no per-namespace config: they inherit the account default. To give one namespace a different cap, set an override (opt-in), keyed by the exact namespace string. Pass null (or both null) to clear an override and fall back to the default.

await oblien.cdn.setNamespaceQuota('customer-123', {
  cdn_max_bytes: 5 * 1024 ** 3,       // this namespace: 5 GB stored at once
  cdn_monthly_bytes: 20 * 1024 ** 3,  // …and 20 GB uploaded per month
});

// which namespaces are actually in use, and their caps/footprint:
const { data } = await oblien.cdn.namespaces({ search: 'customer' });
// data.namespaces → [{ namespace, files, active_bytes, limits, override, has_override }, …]
PUT /cdn/namespaces/quota
X-Client-ID: <id>
X-Client-Secret: <secret>
Content-Type: application/json

{ "namespace": "customer-123", "cdn_max_bytes": 5368709120, "cdn_monthly_bytes": 21474836480 }

GET /cdn/namespaces?search=customer      # in-use namespaces + caps + footprint
curl -X PUT "https://api.oblien.com/cdn/namespaces/quota" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"namespace":"customer-123","cdn_max_bytes":5368709120,"cdn_monthly_bytes":21474836480}'

In the dashboard: CDN → Namespaces lists the namespaces actually in use (with file counts + caps) and lets you set an override or rely on the default.

Account defaults

Instead of configuring every namespace, set account-level defaults once. Any namespace without its own cap inherits the default; a namespace's explicit resource_limits cap always overrides it. So the effective cap is: the namespace's own cap if set → else the account default → else unlimited.

// read the current defaults
const { data } = await oblien.cdn.quotaDefaults();
// data → { cdn_max_bytes, cdn_monthly_bytes }   (null = no default)

// set them (null clears a default → unlimited unless a namespace sets its own)
await oblien.cdn.setQuotaDefaults({
  cdn_max_bytes: 2 * 1024 ** 3,       // every namespace defaults to 2 GB stored
  cdn_monthly_bytes: 10 * 1024 ** 3,  // …and 10 GB uploaded per month
});
GET /cdn/quota-defaults
PUT /cdn/quota-defaults    { "cdn_max_bytes": 2147483648, "cdn_monthly_bytes": 10737418240 }
X-Client-ID: <id>
X-Client-Secret: <secret>
curl "https://api.oblien.com/cdn/quota-defaults" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

curl -X PUT "https://api.oblien.com/cdn/quota-defaults" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{"cdn_max_bytes":2147483648,"cdn_monthly_bytes":10737418240}'

In the dashboard: CDN → Namespaces → Default CDN quota (and each namespace row shows whether it uses its own cap or inherits the default).

Enforcement

Enforced at token issuance, not at upload time:

  • On POST /cdn/token, Oblien checks the namespace's current active storage and this month's ingest against its effective cap (its own cap if set, else the account default). If either is reached it refuses to mint the token with 403 quota_exceeded plus a reason of "storage" or "monthly".
  • Otherwise the permit embeds the remaining allowance as maxBytes (the smaller of the two remainings), and the CDN node caps the file locally.

No shared state on the CDN nodes, so it scales across any number of them. Each short-lived permit is bounded, so concurrent permits can only overshoot by a small, bounded amount (not a hard atomic reservation).

Handle 403 quota_exceeded from /cdn/token — check reason (storage vs monthly) and prompt the user to free space, wait for the month to reset, or raise the limit. Storage caps limit what you keep; traffic limits separately limit what you serve (and can suspend delivery).

Usage

Per-namespace usage, filterable by month:

const { data } = await oblien.cdn.usage({ namespace: 'customer-123', period: '2026-07' });
// data → {
//   namespace, period: '2026-07',
//   ingest: { bytes, files },   // uploaded in that month (counts even if later deleted)
//   active: { bytes, files },   // current live footprint (incl. variants)
//   limits:           { cdn_max_bytes, cdn_monthly_bytes },  // EFFECTIVE (own else default)
//   namespace_limits: { cdn_max_bytes, cdn_monthly_bytes },  // explicit override (null = inheriting)
//   defaults:         { cdn_max_bytes, cdn_monthly_bytes }   // account default (the fallback)
// }
GET /cdn/usage?namespace=customer-123&period=2026-07
X-Client-ID: <id>
X-Client-Secret: <secret>
curl "https://api.oblien.com/cdn/usage?namespace=customer-123&period=2026-07" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

period defaults to the current month. Omit namespace (admin/dashboard keys) to aggregate across all of your namespaces; limits is included when scoped to a single namespace.

Windowed series

For a chart, GET /cdn/usage/series returns a zero-filled ingest series (bytes + files per bucket):

const { data } = await oblien.cdn.usageSeries({
  namespace: 'customer-123',
  interval: 'day',   // 'day' | 'month'
  days: 30,          // or months: 12
});
// data.series → [{ bucket: '2026-07-01', bytes, files }, …]  (zero-filled)
GET /cdn/usage/series?namespace=customer-123&interval=day&days=30
X-Client-ID: <id>
X-Client-Secret: <secret>
curl "https://api.oblien.com/cdn/usage/series?namespace=customer-123&interval=day&days=30" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"