Namespaces
Namespaces let you organize workspaces into isolated groups with their own resource limits, spending quotas, and lifecycle controls. Every workspace belongs to a namespace - if you don't specify one, it goes into the default namespace.
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.
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:
| Concern | How namespaces help |
|---|---|
| Isolation | Workspaces in different namespaces are fully separated |
| Resource caps | Max vCPUs, RAM, disk, and workspace count per namespace |
| Spending quotas | Monthly or daily credit limits per service per namespace |
| Overdraft | Grace zone beyond the quota - block new requests or auto-stop workspaces |
| Default templates | Auto-apply quota configs to every new namespace |
| Lifecycle control | Suspend, activate, or stop all workspaces in a namespace at once |
| Audit trail | Activity log per namespace - who did what, when |
| Usage analytics | Per-namespace credit burn, service breakdown, daily timeline |
SaaS pattern
The most common pattern: your backend creates one namespace per customer. When a customer upgrades to a higher plan, you update the namespace's resource limits and quotas. Your AI agent creates workspaces inside the customer's namespace - it can never exceed the caps you set.
// 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,
},
});
// Set spending limit. Quotas do not auto-reset — call resetQuota when you
// bill the customer (monthly, on contract renewal, etc.) and the threshold
// webhooks re-arm for the next cycle.
await client.namespaces.setQuota({
namespace: ns.data.slug,
service: 'sandbox',
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: 'node-20',
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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name |
slug | string | No | URL-safe identifier. Auto-generated from name if omitted |
description | string | No | Free-text description |
type | string | No | "default", "production", "staging", "development", "testing" |
isDefault | boolean | No | Mark as the default namespace for new workspaces |
metadata | object | No | Arbitrary key-value data |
tags | string[] | No | Tags for filtering and organization |
resource_limits | object | No | Resource caps (see below) |
Resource limits
| Field | Type | Description |
|---|---|---|
max_workspaces | number | null | Max workspaces in namespace. null = inherit plan limit |
max_vcpus | number | null | Max vCPU cores per workspace |
max_ram_mb | number | null | Max memory per workspace in MB |
max_disk_gb | number | null | Max writable disk per workspace in GB |
Resource limits are validated against your plan caps - you can't set a namespace limit higher than what your plan allows.
Enforcement. These limits are enforced at two points:
- Workspace create — a create in the namespace is rejected (
409 NAMESPACE_LIMIT_REACHED) if it would exceedmax_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.
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
| Code | Status | Cause |
|---|---|---|
validation_error | 400 | name is missing or the slug derived from input is invalid |
namespace_limit_exceeded | 409 | Maximum 100 namespaces per account |
namespace_exists | 409 | Slug already exists for your account |
plan_limit_exceeded | 400 | Requested resource_limits exceed your current plan caps |
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.
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
| Code | Status | Cause |
|---|---|---|
validation_error | 400 | Neither name nor slug was provided, or the derived slug is invalid |
plan_limit_exceeded | 400 | Requested resource_limits exceed your current plan caps |
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_atcurl "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
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Results per page (max 100) |
offset | number | 0 | Pagination offset |
status | string | - | Filter: "active", "inactive", "suspended" |
type | string | - | Filter by namespace type |
search | string | - | Search name and slug |
sortBy | string | "created_at" | "name", "created_at", "updated_at" |
sortOrder | string | "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/:identifiercurl "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
| Field | Type | Description |
|---|---|---|
name | string | Display name |
description | string | Description |
status | string | "active", "inactive", "suspended" |
type | string | Namespace type |
tags | string[] | Tags |
metadata | object | Key-value metadata |
resource_limits | object | Resource 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
| Parameter | Type | Default | Description |
|---|---|---|---|
deleteWorkspaces | boolean | false | Delete 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/suspendcurl -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/activatecurl -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-workspacescurl -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=0curl "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: 'sandbox',
days: 30,
});GET /namespaces/:id/usage?service=sandbox&days=30curl "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
| Parameter | Type | Default | Description |
|---|---|---|---|
service | string | - | Filter by service ("sandbox", "ai", "deployment", etc.) |
days | number | 30 | Lookback period |
Response
{
"success": true,
"data": {
"usage": [
{ "date": "2026-03-06", "service": "sandbox", "total_requests": 150, "total_credits": 42.5 },
{ "date": "2026-03-07", "service": "sandbox", "total_requests": 200, "total_credits": 55.0 }
],
"summary": [
{ "service": "sandbox", "total_requests": 350, "total_credits": 97.5 }
],
"quotas": [
{
"namespace": "production",
"service": "sandbox",
"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|dayQuery parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
from | ISO8601 | 30 days ago | Range start |
to | ISO8601 | now | Range end |
groupBy | hour | day | day | Bucket 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
}
}
}| Unit | Meaning | Convert to |
|---|---|---|
cpu_time_minutes | vCPU-minutes of compute | vcpu_hours = /60 (provided) |
memory_gb_minutes | GB-minutes of RAM | gb_hours = /60 (provided) |
network_gb | Egress+ingress GB | bytes = × 1e9 |
disk_io_gb | Disk I/O GB | — |
credits | What 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 thecredits.usagewebhook 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.
How quotas work
- Normal zone -
quota_used ≤ quota_limit. Requests proceed normally. - Overdraft zone -
quota_limit < quota_used ≤ quota_limit + overdraft. Requests still succeed, but the API returns a warning header. This is your grace buffer. - Hard block -
quota_used > quota_limit + overdraft. New requests are rejected with HTTP 402. IfonOverdraftActionis"stop_workspaces", all running workspaces in the namespace are also stopped.
Renewal model
We meter, you renew. Quotas don't auto-reset on any cadence — your customers' billing cycles (monthly, quarterly, on contract renewal, prepaid top-up, never) are yours to model. The platform only tracks how much each namespace has consumed and fires webhooks; calling resetQuota is what closes one cycle and starts the next. This also re-arms namespace.quota.threshold notifications so each new cycle gets its own warnings.
Near-limit notifications
The namespace.quota.threshold webhook fires when quota_used crosses one of the percentages you configure. Use it to email your customer, push an in-app banner, or trigger an automatic top-up before they hit the hard limit.
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 at most once between resets — there's no flood when usage hovers at the limit. resetQuota (or changing the quota via setQuota) clears the fired state and re-arms every threshold.
Overdraft actions
| Action | Behavior |
|---|---|
block | Reject new credit-consuming requests (HTTP 402). Running workspaces continue. |
stop_workspaces | Reject new requests and stop all running workspaces in the namespace. |
Set quota
await client.namespaces.setQuota({
namespace: 'production',
service: 'sandbox',
quotaLimit: 500,
overdraft: 50,
onOverdraftAction: 'stop_workspaces',
notificationThresholds: [50, 80, 95],
});POST /credits/namespace-quota{
"namespace": "production",
"service": "sandbox",
"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": "sandbox",
"quotaLimit": 500,
"overdraft": 50,
"onOverdraftAction": "stop_workspaces",
"notificationThresholds": [50, 80, 95]
}'Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
namespace | string | Yes | Namespace slug |
service | string | Yes | Service name: "sandbox", "ai", "deployment", etc. |
quotaLimit | number | Yes | Credit limit (max 10,000,000) |
overdraft | number | No | Grace zone credits beyond the limit. Default: 0 |
onOverdraftAction | string | No | "block" or "stop_workspaces". Default: "block" |
notificationThresholds | number[] | null | No | Percentages that fire namespace.quota.threshold. Omit or null for system defaults ([80, 95]). [] disables. Calling setQuota re-arms thresholds. |
Quotas do not auto-reset. Call resetQuota when you bill the customer — that re-arms the notification thresholds for the next cycle.
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 — the platform never resets quotas on its own.
await client.namespaces.resetQuota({
namespace: 'production',
service: 'sandbox',
});POST /credits/reset-quota{ "namespace": "production", "service": "sandbox" }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": "sandbox" }'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=20curl "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=30curl "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: 'sandbox',
quotaLimit: 100,
autoApply: true,
});POST /credits/defaults{
"level": "namespace",
"service": "sandbox",
"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": "sandbox",
"quotaLimit": 100,
"autoApply": true
}'Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
service | string | Yes | Service name |
quotaLimit | number | Yes | Credit limit |
autoApply | boolean | No | Auto-apply to new namespaces. Default: true |
Get default quota
const config = await client.namespaces.getDefaultQuota('sandbox');GET /credits/defaults?level=namespace&service=sandboxcurl "https://api.oblien.com/credits/defaults?level=namespace&service=sandbox" \
-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=namespacecurl "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('sandbox');DELETE /credits/defaults{ "level": "namespace", "service": "sandbox" }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": "sandbox" }'Toggle auto-apply
// Enable auto-apply
await client.namespaces.toggleDefaultQuotaAutoApply('sandbox', true);
// Disable auto-apply
await client.namespaces.toggleDefaultQuotaAutoApply('sandbox', false);POST /credits/defaults/toggle-auto-apply{ "level": "namespace", "service": "sandbox", "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": "sandbox", "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; // "sandbox", "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
| Limit | Value |
|---|---|
| Max namespaces per account | 100 |
| Max quota limit value | 10,000,000 credits |
| Max activity log page size | 100 |
| Valid overdraft actions | block, stop_workspaces |
| Valid statuses | active, inactive, suspended |
| Max notification thresholds per quota | 10 (each in (0, 100]) |