API Reference

Namespaces

For the complete payment-to-VM flow, see Build a SaaS or VM reseller. max_workspaces caps the number of workspaces in this namespace; CPU, RAM and disk limits cap each individual workspace. Set max_total_vcpus, max_total_ram_mb and max_total_disk_gb to also bound their combined allocation, including stopped workspaces and pending resizes.

Namespaces let you organize workspaces into isolated groups with their own resource limits, billing contracts and lifecycle controls. Omitting namespace creates a personal account workspace with namespace: null. A namespace literally named default is a separate named namespace; it is not an implicit billing destination.

For current compute, purchase capped PAYG or monthly capacity for the namespace. Resource policies remain applicable, while a paid monthly pool has no second credit allowance. Existing credit-based contracts keep their saved quota and renewal rules. A policy edit alone does not purchase or migrate a billing contract.

TL;DR - Namespaces are how you build multi-tenant SaaS on Oblien. Assign one namespace per customer, team, or environment. Set resource caps (max vCPUs, RAM, workspaces) so no single tenant can exhaust your plan. Add spending quotas with overdraft policies so your agent or backend can manage plans cleanly - block requests, stop workspaces, or allow a grace zone before hard-cutting. Default quotas auto-apply to new namespaces so every new customer starts with the same limits.

Total namespace capacity

Retail namespaces should set explicit per-workspace and total limits. An Enterprise owner does not imply unlimited customer capacity.

{
  "resource_limits": {
    "max_workspaces": 6, "max_vcpus": 2, "max_ram_mb": 6144, "max_disk_gb": 32,
    "max_total_vcpus": 4, "max_total_ram_mb": 8192, "max_total_disk_gb": 128
  }
}

The three max_total_* fields bound the combined allocated CPU quota, RAM (MB) and disk (GB). Stored/stopped VMs, build VMs, managed disks and pending resource changes count. Resource caps are independent of credit balances. A top-up buys more usage; only an explicit policy/plan change increases capacity. CPU limits accept nonnegative values in steps of 0.001 vCPU; other resource limits use nonnegative integers. null inherits the applicable limit; zero prevents allocation.

Detail and mutation responses include effective_resource_limits and, for capped pools, allocated_resource_usage: { workspaces, vcpus, ram_mb, disk_gb, pending_updates }. These are provider observations, not reservations for the caller. Create/resize admission checks capacity again under database locks. A timeout after a provider write holds the reservation until verification; it does not free capacity for another request. Resource-limit PATCH/PUT updates merge atomically and preserve fields omitted by older clients.

Lowering limits preserves existing data. An allocation already above a new limit may decrease, but cannot grow further. Never automatically shrink a customer's disk to fit a cheaper plan.

Why namespaces

Without namespaces, every workspace shares one flat pool. That's fine for personal use, but breaks down as soon as you have:

  • Multiple customers - each needs isolated workspaces with separate spending limits
  • Multiple environments - production shouldn't compete with staging for resources
  • AI agents managing plans - agents need clean boundaries to enforce customer tiers
  • Cost attribution - you need to know which team or customer burned which credits

Namespaces solve all of these. Each namespace is a boundary for:

ConcernHow namespaces help
IsolationWorkspaces in different namespaces are fully separated
Resource capsMax vCPUs, RAM, disk, and workspace count per namespace
Spending quotasMonthly or daily credit limits per service per namespace
OverdraftGrace zone beyond the quota - block new requests or auto-stop workspaces
Default templatesAuto-apply quota configs to every new namespace
Lifecycle controlSuspend, activate, or stop all workspaces in a namespace at once
Audit trailActivity log per namespace - who did what, when
Usage analyticsPer-namespace credit burn, service breakdown, daily timeline

SaaS pattern

Your backend creates one namespace per customer and resolves it from the authenticated customer's record. Use the billing plan-change APIs for hosted paid subscriptions; policy edits alone must not grant a paid upgrade. The example below is Mode A metered billing, where your backend owns the allowance cycle. For prepaid monthly servers use the monthly reseller flow.

// Customer signs up → create their namespace
const ns = await client.namespaces.create({
  name: `customer-${customerId}`,
  type: 'production',
  resource_limits: {
    max_workspaces: plan.maxWorkspaces,
    max_vcpus: plan.maxCpus,
    max_ram_mb: plan.maxRamMb,
  },
});

// Mode A spending limit. Your backend resets this cycle after external payment.
// Hosted subscription renewal is handled by Oblien's verified payment flow.
await client.namespaces.setQuota({
  namespace: ns.data.slug,
  service: 'workspace_vm',
  quotaLimit: plan.monthlyCredits,
  overdraft: plan.monthlyCredits * 0.1, // 10% grace
  onOverdraftAction: 'stop_workspaces',
  notificationThresholds: [50, 80, 95], // namespace.quota.threshold webhook fires at each
});

// Agent creates workspaces inside the customer's namespace
const workspace = await client.workspaces.create({
  namespace: ns.data.slug,
  image: 'oblien/node:24',
  config: { cpus: 2, memory_mb: 2048 },
});

Agent control pattern

Agents can use namespaces to self-organize work. One namespace per project or per task category, with resource limits that prevent runaway costs:

// Agent creates a scoped environment for a task
const taskNs = await client.namespaces.create({
  name: `task-${taskId}`,
  type: 'staging',
  resource_limits: { max_workspaces: 5, max_vcpus: 4, max_ram_mb: 8192 },
});

// Run workspaces inside it
// ... when done, clean up everything at once
await client.namespaces.delete(taskNs.data.id, { deleteWorkspaces: true });

Create namespace

const res = await client.namespaces.create({
  name: 'production',
  type: 'production',
  description: 'Production customer workloads',
  tags: ['critical', 'auto-scale'],
  resource_limits: {
    max_workspaces: 50,
    max_vcpus: 8,
    max_ram_mb: 16384,
    max_disk_gb: 100,
  },
});
console.log(res.data.id, res.data.slug);
POST /namespaces
{
  "name": "production",
  "type": "production",
  "description": "Production customer workloads",
  "tags": ["critical", "auto-scale"],
  "resource_limits": {
    "max_workspaces": 50,
    "max_vcpus": 8,
    "max_ram_mb": 16384,
    "max_disk_gb": 100
  }
}
curl -X POST https://api.oblien.com/namespaces \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production",
    "type": "production",
    "resource_limits": { "max_workspaces": 50, "max_vcpus": 8 }
  }'

Parameters

ParameterTypeRequiredDescription
namestringYesDisplay name
slugstringNoURL-safe identifier. Auto-generated from name if omitted
descriptionstringNoFree-text description
typestringNo"default", "production", "staging", "development", "testing"
isDefaultbooleanNoMark as the default namespace for new workspaces
metadataobjectNoArbitrary key-value data
tagsstring[]NoTags for filtering and organization
resource_limitsobjectNoResource caps (see below)

Resource limits

FieldTypeDescription
max_workspacesnumber | nullMax workspaces in namespace. null = inherit plan limit
max_vcpusnumber | nullMax vCPU cores per workspace
max_ram_mbnumber | nullMax memory per workspace in MB
max_disk_gbnumber | nullMax writable disk per workspace in GB

Declare policy directly. max_vcpus and max_total_vcpus accept values in steps of 0.001 vCPU, such as 0.25 or 5.5. Other workspace resource limits must be integers. Values range from 0 to 1,000,000,000, or null to inherit; invalid values and unknown keys return 400 invalid_resource_limits. Zero denies that allocation. null inherits Oblien capacity and does not remove a saved paid restriction. A declaration above current account or machine capacity is accepted without allocating resources.

Create, ensure, detail and update responses include data.resource_limits (the saved declaration) and data.effective_resource_limits (resolved by Oblien). The effective cap is the strictest applicable declared, paid-offer, account and platform cap. For example, a declared 200-vCPU limit under an Enterprise account resolves to at most 12 vCPUs per VM; a stricter paid limit of 2 resolves to 2. Use max_total_vcpus for a larger CPU pool shared across multiple workspaces. Enterprise, inherited limits and reseller offers cannot raise the per-workspace platform ceiling. Clients submit policy without calculating this intersection. Account pool usage, credits and physical host availability are checked when work is requested.

Enforcement. Oblien checks these caps when resources are requested:

  • Workspace create — a create in the namespace is rejected (409 NAMESPACE_LIMIT_REACHED) if it would exceed max_workspaces, or if its requested vCPU / RAM / disk exceeds the per-workspace cap.
  • Workspace upgrade — changing a workspace's resources is rejected the same way if the new values exceed the per-workspace caps.
  • Start, resume, restart, wake and snapshot resume — the existing allocation must still fit the effective caps before it can run.

The max_workspaces check is atomic: concurrent creates in the same namespace are serialised (the namespace row is locked and the count re-checked inside the same transaction as the insert), so the cap can never be exceeded by a race.

Resource limits are distinct from credit quotas (below): limits cap how much a namespace can provision; quotas cap how much it can spend. Quotas are usage-based — an over-quota namespace is suspended (blocking new creates/starts) and emits namespace.quota.threshold / credits.depleted webhooks rather than being pre-reserved at create.

Response 201

{
  "success": true,
  "data": {
    "id": "ns_a1b2c3d4e5f6",
    "client_id": "cl_xyz",
    "name": "production",
    "slug": "production",
    "description": "Production customer workloads",
    "status": "active",
    "type": "production",
    "is_default": false,
    "metadata": {},
    "tags": ["critical", "auto-scale"],
    "resource_limits": {
      "max_workspaces": 50,
      "max_vcpus": 8,
      "max_ram_mb": 16384,
      "max_disk_gb": 100
    },
    "created_at": "2026-03-07T10:00:00Z",
    "updated_at": "2026-03-07T10:00:00Z",
    "last_active_at": null
  }
}

Errors

CodeStatusCause
validation_error400name is missing or the slug derived from input is invalid
namespace_limit_exceeded409The owner account's namespace count limit has been reached
namespace_exists409Slug already exists for your account
invalid_resource_limits400Resource policy has unknown fields or invalid numeric values

Ensure namespace

Create the namespace if it does not exist. If a namespace with the same slug already exists for your account, the existing record is returned instead.

Creation and ensure share an atomic account namespace-count check. The owner row is locked and the count is checked in the same transaction that inserts the namespace. An existing namespace can still be ensured at the limit. The limit comes from the owner's account tier; Enterprise has no namespace count cap. This is separate from max_workspaces, which limits workspaces inside one namespace.

const res = await client.namespaces.ensure({
  name: 'production',
  type: 'production',
});

console.log(res.created ? 'created' : 'reused', res.data.slug);
POST /namespaces/ensure
{
  "name": "production",
  "type": "production"
}
curl -X POST https://api.oblien.com/namespaces/ensure \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production",
    "type": "production"
  }'

Response

{
  "success": true,
  "created": false,
  "data": {
    "id": "ns_a1b2c3d4e5f6",
    "slug": "production",
    "status": "active"
  }
}

created: true means a new namespace was inserted. created: false means an existing namespace was reused.

Errors

CodeStatusCause
validation_error400Neither name nor slug was provided, or the derived slug is invalid
invalid_resource_limits400Resource policy has unknown fields or invalid numeric values
namespace_limit_exceeded409A new namespace would exceed the owner account's namespace count limit

List namespaces

const { data, pagination } = await client.namespaces.list({
  status: 'active',
  search: 'prod',
  sortBy: 'created_at',
  sortOrder: 'DESC',
  limit: 20,
  offset: 0,
});
console.log(`${pagination.total} namespaces total`);
GET /namespaces?status=active&search=prod&limit=20&sortBy=created_at
curl "https://api.oblien.com/namespaces?status=active&limit=20" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Query parameters

ParameterTypeDefaultDescription
limitnumber50Results per page (max 100)
offsetnumber0Pagination offset
statusstring-Filter: "active", "inactive", "suspended"
typestring-Filter by namespace type
searchstring-Search name and slug
sortBystring"created_at""name", "created_at", "updated_at"
sortOrderstring"DESC""ASC" or "DESC"

Response

{
  "success": true,
  "data": [ /* NamespaceData[] */ ],
  "pagination": { "total": 42, "limit": 20, "offset": 0 }
}

Get namespace

Retrieve a namespace by ID or slug.

// By slug
const ns = await client.namespaces.get('production');

// By ID
const ns = await client.namespaces.get('ns_a1b2c3d4e5f6');
GET /namespaces/:identifier
curl "https://api.oblien.com/namespaces/production" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Response

{
  "success": true,
  "data": { /* NamespaceData */ }
}

Update namespace

const updated = await client.namespaces.update('ns_a1b2c3d4e5f6', {
  description: 'Updated description',
  tags: ['production', 'us-east'],
  resource_limits: { max_workspaces: 100 },
});
PUT /namespaces/:id
{
  "description": "Updated description",
  "tags": ["production", "us-east"],
  "resource_limits": { "max_workspaces": 100 }
}
curl -X PUT "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "description": "Updated", "resource_limits": { "max_workspaces": 100 } }'

Updatable fields

FieldTypeDescription
namestringDisplay name
descriptionstringDescription
statusstring"active", "inactive", "suspended"
typestringNamespace type
tagsstring[]Tags
metadataobjectKey-value metadata
resource_limitsobjectResource caps

Delete namespace

Permanently delete a namespace. Optionally delete all workspaces in it.

// Delete namespace only (workspaces remain, moved to default)
await client.namespaces.delete('ns_a1b2c3d4e5f6');

// Delete namespace AND all its workspaces
await client.namespaces.delete('ns_a1b2c3d4e5f6', { deleteWorkspaces: true });
DELETE /namespaces/:id
{ "deleteWorkspaces": true }
curl -X DELETE "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "deleteWorkspaces": true }'

Parameters

ParameterTypeDefaultDescription
deleteWorkspacesbooleanfalseDelete all workspaces in the namespace

When deleteWorkspaces is true, all workspaces, their data, snapshots, and logs are permanently destroyed. This is irreversible.


Suspend namespace

Suspend a namespace - sets status to suspended and stops all running workspaces. No new workspaces can be created in a suspended namespace.

await client.namespaces.suspend('ns_a1b2c3d4e5f6');
POST /namespaces/:id/suspend
curl -X POST "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6/suspend" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Response

{
  "success": true,
  "message": "Namespace suspended",
  "stoppedWorkspaces": 3
}

Activate namespace

Reactivate a suspended namespace. Sets status back to active. Workspaces are not automatically restarted - you need to start them individually.

await client.namespaces.activate('ns_a1b2c3d4e5f6');
POST /namespaces/:id/activate
curl -X POST "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6/activate" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Stop all workspaces

Stop every running workspace in the namespace without changing namespace status. Useful for cost control - stop the workloads but keep the namespace active for new creations.

await client.namespaces.stopWorkspaces('ns_a1b2c3d4e5f6');
POST /namespaces/:id/stop-workspaces
curl -X POST "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6/stop-workspaces" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Activity log

Get the audit trail for a namespace - creation, updates, suspensions, and other lifecycle events.

const res = await client.namespaces.activity('ns_a1b2c3d4e5f6', {
  limit: 20,
  offset: 0,
});
GET /namespaces/:id/activity?limit=20&offset=0
curl "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6/activity?limit=20" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Response

{
  "success": true,
  "data": [
    {
      "id": 1,
      "namespace_id": "ns_a1b2c3d4e5f6",
      "user_id": "cl_xyz",
      "action": "created",
      "description": "Namespace created",
      "changes": { "name": "production", "type": "production" },
      "ip_address": "203.0.113.1",
      "created_at": "2026-03-07T10:00:00Z"
    },
    {
      "id": 2,
      "action": "updated",
      "description": "Namespace updated",
      "changes": { "description": ["", "Production workloads"] },
      "created_at": "2026-03-07T10:05:00Z"
    }
  ]
}

Usage statistics

Get credit usage for a namespace - daily breakdown by service.

const res = await client.namespaces.usage('ns_a1b2c3d4e5f6', {
  service: 'workspace_vm',
  days: 30,
});
GET /namespaces/:id/usage?service=workspace_vm&days=30
curl "https://api.oblien.com/namespaces/ns_a1b2c3d4e5f6/usage?days=30" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Query parameters

ParameterTypeDefaultDescription
servicestring-Filter by service ("workspace_vm", "ai", "deployment", etc.)
daysnumber30Lookback period

Response

{
  "success": true,
  "data": {
    "usage": [
      { "date": "2026-03-06", "service": "workspace_vm", "total_requests": 150, "total_credits": 42.5 },
      { "date": "2026-03-07", "service": "workspace_vm", "total_requests": 200, "total_credits": 55.0 }
    ],
    "summary": [
      { "service": "workspace_vm", "total_requests": 350, "total_credits": 97.5 }
    ],
    "quotas": [
      {
        "namespace": "production",
        "service": "workspace_vm",
        "quota_limit": 500,
        "quota_used": 97.5,
        "overdraft": 50,
        "on_overdraft_action": "stop_workspaces",
        "notification_thresholds": [80, 95],
        "last_threshold_fired": null
      }
    ]
  }
}

The usage / summary figures above are denominated in credits (Oblien's converted units), grouped by service. For raw metered units — to run your own billing — use the endpoint below.


Raw usage units (for external billing)

Returns the raw metered resource units consumed by a namespace over a time range — not credits — so an external biller can apply its own conversion rates. Time-bucketed, with summed totals. The figures are deterministic for a given range, so you can poll and idempotency-key on (namespace, bucket.timestamp).

GET /namespaces/{id}/usage-units?from=<iso>&to=<iso>&groupBy=hour|day

Query parameters

ParameterTypeDefaultDescription
fromISO860130 days agoRange start
toISO8601nowRange end
groupByhour | daydayBucket granularity

Response

{
  "success": true,
  "data": {
    "namespace": "production",
    "range": { "from": "2026-06-01T00:00:00.000Z", "to": "2026-06-21T00:00:00.000Z" },
    "group_by": "day",
    "buckets": [
      {
        "timestamp": "2026-06-20",
        "cpu_time_minutes": 4321.5,
        "memory_gb_minutes": 8800.0,
        "disk_io_gb": 12.4,
        "network_gb": 3.1,
        "vcpu_hours": 72.025,
        "gb_hours": 146.667,
        "credits": 540.2,
        "records": 96
      }
    ],
    "totals": {
      "cpu_time_minutes": 4321.5, "memory_gb_minutes": 8800.0,
      "disk_io_gb": 12.4, "network_gb": 3.1,
      "vcpu_hours": 72.025, "gb_hours": 146.667,
      "credits": 540.2, "records": 96
    }
  }
}
UnitMeaningConvert to
cpu_time_minutesvCPU-minutes of computevcpu_hours = /60 (provided)
memory_gb_minutesGB-minutes of RAMgb_hours = /60 (provided)
network_gbEgress+ingress GBbytes = × 1e9
disk_io_gbDisk I/O GB—
creditsWhat Oblien charged (informational)—

Edge metrics (requests, bandwidth in/out) live on the edge plane — get them per namespace via the Analytics home summary (?ns=<slug>). This endpoint covers the compute plane. The same raw units are also pushed per billing cycle on the credits.usage webhook if you prefer push over poll.


Quotas & Overdraft

Quotas let you set spending limits on a per-namespace, per-service basis. Combined with overdraft policies, they give you fine-grained control over how much each namespace can spend and what happens when it hits the limit.

GET /namespaces/:id/usage returns quota amounts as JSON numbers, preserving fractional credits. quota_limit: null means unlimited; quota_limit: 0 means zero included credits. The paid allowance is quota_limit + purchased_credits. The dashboard includes purchased top-ups when displaying that allowance. Different service quotas are separate: workspace metering uses workspace_vm; a separate compute quota does not add credits to it.

How quotas work

Let ceiling = quota_limit + purchased_credits and balance = ceiling + overdraft - quota_used for an enabled, capped quota.

  1. Normal zone — usage is at or below the paid ceiling and balance is positive.
  2. Overdraft zone — usage is above the paid ceiling, but balance is still positive.
  3. Exhausted — balance is zero or negative. New credit-consuming requests are rejected with HTTP 402. A request may spend the last available credits; the next request is blocked. Usage that already happened is still recorded.

With onOverdraftAction: "stop_workspaces", usage beyond ceiling + suspendThreshold also suspends the namespace and stops its workspaces. Disabled quotas do not enforce these limits.

Renewal model

For allowances you manage directly, call resetQuota when your customer's new cycle begins. This resets usage and re-arms namespace.quota.threshold notifications. For a namespace with an Oblien-hosted reseller subscription, Oblien applies the saved offer and resets cycle usage after a verified paid renewal invoice; purchased top-ups survive renewal. Read /billing/subscription for that subscription's billing period.

Near-limit notifications

The namespace.quota.threshold webhook fires when quota_used crosses a configured percentage of quota_limit + purchased_credits. Use it to email your customer and show a banner with an option to buy credits. The debit, marker and alert commit together; signed delivery retries durably. Read the quota row’s alert field, or quota.alert on billing entitlement, for the current state. See the alert and recovery contract.

  • notificationThresholds: null (default) — system defaults [80, 95] apply.
  • notificationThresholds: [50, 80, 95] — fire at each percentage in order.
  • notificationThresholds: [] — disabled, no near-limit webhooks.

Each threshold fires once until re-armed: a cycle reset clears the fired state, while a top-up or usage refund that lowers the usage percentage below a band re-arms that band. A large debit reports the highest crossed band, grace entry, or exhaustion. Custom percentages survive paid renewals. credits.depleted is still emitted when percentage warnings are disabled.

Overdraft actions

ActionBehavior
blockReject new credit-consuming requests (HTTP 402). Running workspaces continue.
stop_workspacesReject new requests and stop all running workspaces in the namespace.

Set quota

await client.namespaces.setQuota({
  namespace: 'production',
  service: 'workspace_vm',
  quotaLimit: 500,
  overdraft: 50,
  onOverdraftAction: 'stop_workspaces',
  notificationThresholds: [50, 80, 95],
});
POST /credits/namespace-quota
{
  "namespace": "production",
  "service": "workspace_vm",
  "quotaLimit": 500,
  "overdraft": 50,
  "onOverdraftAction": "stop_workspaces",
  "notificationThresholds": [50, 80, 95]
}
curl -X POST https://api.oblien.com/credits/namespace-quota \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "production",
    "service": "workspace_vm",
    "quotaLimit": 500,
    "overdraft": 50,
    "onOverdraftAction": "stop_workspaces",
    "notificationThresholds": [50, 80, 95]
  }'

Parameters

ParameterTypeRequiredDescription
namespacestringYesNamespace slug
servicestringYesService name: "workspace_vm", "ai", "deployment", etc.
quotaLimitnumberYesCredit limit (max 10,000,000)
overdraftnumberNoGrace zone credits beyond the limit. Default: 0
onOverdraftActionstringNo"block" or "stop_workspaces". Default: "block"
notificationThresholdsnumber[] | nullNoPercentages that fire namespace.quota.threshold. Omit or null for system defaults ([80, 95]). [] disables. Calling setQuota re-arms thresholds.

Mode A quotas reset when your backend starts a new paid cycle. Oblien-hosted Mode B subscriptions reset after verified paid renewal invoices; do not reset those manually.

Reset quota

Reset quota_used back to zero and re-arm namespace.quota.threshold webhooks. Call this at the start of each of your customers' billing cycles when you manage payment yourself. For VM billing, prefer client.billing.resetQuota(namespace, { periodEnd }) for an idempotent cycle reset. Oblien-hosted subscriptions reset automatically on each paid cycle; do not reset them manually.

await client.namespaces.resetQuota({
  namespace: 'production',
  service: 'workspace_vm',
});
POST /credits/reset-quota
{ "namespace": "production", "service": "workspace_vm" }
curl -X POST https://api.oblien.com/credits/reset-quota \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "namespace": "production", "service": "workspace_vm" }'

List with quota data

List namespaces enriched with spending and quota information - total credits consumed, active quotas, and per-service breakdown.

const res = await client.namespaces.listWithQuotas({
  status: 'active',
  limit: 20,
});
GET /credits/namespaces?status=active&limit=20
curl "https://api.oblien.com/credits/namespaces?status=active&limit=20" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Get detailed quota info

Comprehensive namespace financial details - quotas, usage stats, service breakdown, daily timeline, and recent transactions. Up to 90 days lookback.

const details = await client.namespaces.getDetails('production', { days: 30 });
GET /credits/namespaces/:namespace?days=30
curl "https://api.oblien.com/credits/namespaces/production?days=30" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Default Quotas

Default quotas are templates that auto-apply to new namespaces. When a namespace first consumes credits for a service and no quota exists, the system checks for a default config. If autoApply is enabled, it creates a quota from the template — including overdraft and notification-threshold settings inherited from the per-namespace defaults.

This is how you set a baseline for every customer namespace without configuring each one manually.

Set default quota

await client.namespaces.setDefaultQuota({
  service: 'workspace_vm',
  quotaLimit: 100,
  autoApply: true,
});
POST /credits/defaults
{
  "level": "namespace",
  "service": "workspace_vm",
  "quotaLimit": 100,
  "autoApply": true
}
curl -X POST https://api.oblien.com/credits/defaults \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "level": "namespace",
    "service": "workspace_vm",
    "quotaLimit": 100,
    "autoApply": true
  }'

Parameters

ParameterTypeRequiredDescription
servicestringYesService name
quotaLimitnumberYesCredit limit
autoApplybooleanNoAuto-apply to new namespaces. Default: true

Get default quota

const config = await client.namespaces.getDefaultQuota('workspace_vm');
GET /credits/defaults?level=namespace&service=workspace_vm
curl "https://api.oblien.com/credits/defaults?level=namespace&service=workspace_vm" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Get all default quotas

const configs = await client.namespaces.getAllDefaultQuotas();
GET /credits/defaults/all?level=namespace
curl "https://api.oblien.com/credits/defaults/all?level=namespace" \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET"

Delete default quota

await client.namespaces.deleteDefaultQuota('workspace_vm');
DELETE /credits/defaults
{ "level": "namespace", "service": "workspace_vm" }
curl -X DELETE https://api.oblien.com/credits/defaults \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "level": "namespace", "service": "workspace_vm" }'

Toggle auto-apply

// Enable auto-apply
await client.namespaces.toggleDefaultQuotaAutoApply('workspace_vm', true);

// Disable auto-apply
await client.namespaces.toggleDefaultQuotaAutoApply('workspace_vm', false);
POST /credits/defaults/toggle-auto-apply
{ "level": "namespace", "service": "workspace_vm", "autoApply": true }
curl -X POST https://api.oblien.com/credits/defaults/toggle-auto-apply \
  -H "X-Client-ID: $OBLIEN_CLIENT_ID" \
  -H "X-Client-Secret: $OBLIEN_CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{ "level": "namespace", "service": "workspace_vm", "autoApply": true }'

Namespace object

All namespace endpoints return this shape:

interface NamespaceData {
  id: string;                     // "ns_a1b2c3d4e5f6"
  client_id: string;
  name: string;
  slug: string;                   // URL-safe, unique per account
  description?: string;
  status: 'active' | 'inactive' | 'suspended';
  type: string;                   // "default", "production", "staging", etc.
  is_default: boolean;
  metadata?: Record<string, unknown>;
  tags?: string[];
  resource_limits?: {
    max_workspaces?: number | null;
    max_vcpus?: number | null;
    max_ram_mb?: number | null;
    max_disk_gb?: number | null;
  } | null;
  created_at: string;
  updated_at: string;
  last_active_at?: string;
}

Quota object

interface NamespaceQuota {
  id: number;
  client_id: string;
  namespace: string;              // Matches namespace slug
  service: string;                // "workspace_vm", "ai", "deployment", etc.
  quota_limit: number | null;     // null = unlimited
  quota_used: number;
  overdraft: number;              // Grace zone beyond limit
  on_overdraft_action: 'block' | 'stop_workspaces';
  // Webhook thresholds: null = system defaults [80, 95]; [] = disabled
  notification_thresholds: number[] | null;
  // Highest threshold fired this cycle; cleared by resetQuota / setQuota
  last_threshold_fired: number | null;
  enabled: boolean;
  created_at: string;
  updated_at: string;
}

Limits

LimitValue
Max namespaces per account100
Max quota limit value10,000,000 credits
Max activity log page size100
Valid overdraft actionsblock, stop_workspaces
Valid statusesactive, inactive, suspended
Max notification thresholds per quota10 (each in (0, 100])