Projects
Projects are isolated workspaces. Each project has its own provider allow-list, routing rules, budgets, environments, and API keys. Use them to separate dev/staging/production or different products.
Managing projects
// List
const { projects } = await client.projects.list();
// Create
const project = await client.projects.create({
name: 'My App',
slug: 'my-app', // optional URL-safe identifier
description: 'Production AI', // optional
});
// Update
await client.projects.update(project.id, { name: 'My App v2' });
// Delete
await client.projects.delete(project.id);
With a project-scoped API key
A client created with a project-scoped API key works inside that project only:
client.projects.list() returns just the key's project, and client.project(id) works for that project alone (any other
project is not found, 404). The key can read the project's settings, but creating, updating or
deleting projects, and changing a project's settings, needs an owner's or admin's session (403).
Organization-level calls such as client.providers, client.routing.getConfig() and
client.keys are refused with 403. client.requests.list(), client.routing.listHistory() and client.usage
cover the key's project only, and client.requests.get() or client.routing.getDecision() on a request of another
project (or of no project) is not found, 404. See
Project-scoped API keys.
Project-scoped sub-client
Once you have a project ID, use client.project(id) to get a sub-client for all project-level operations:
const proj = client.project('proj_abc123');
Connections (project provider allow-list)
Project connections restrict which providers this project's requests may use. There's no API key
here, just a providerId. This is a different
concept from the org-level client.providers namespace (see Providers), which
is where you actually connect your own key (BYOK); a project's allow-list applies on top of
whatever providers your org already has access to, whether that's a platform-connected
provider or one you've connected yourself with your own key. If a project sets an explicit
allow-list, any provider not on it, including a BYOK provider, is excluded from that
project's requests. Only enabled connections count. A request none of them can serve, or any
request of a project whose connections are all disabled, is refused with 422 no_available_model.
allowedModels is saved with the connection but not enforced yet. To limit the project's models,
use its policy's allowedModels.
// Restrict this project to a platform-connected provider
await proj.connections.add({
providerId: 'openai',
enabled: true,
});
// List this project's allow-list
const { providers } = await proj.connections.list();
// Toggle
await proj.connections.disable('openai');
await proj.connections.enable('openai');
// Remove it from the list; with no connections left, the project may use every provider again
await proj.connections.remove('openai');
Project routing
Each project can override the org-level routing strategy. Project-level config
only covers mode, strategy, weights, provider order/affinity, aliases, regions and the Speed setting. The governance
policy block (blocked providers, cost/latency ceilings, fallbackBehavior, etc.) is
org-level only and has no project override today: the project's allowedRegions and its policy can only
narrow it. What each setting does: Cost, latency and quality controls.
Once a project has a routing config, its mode and strategy replace the organization's for that project's requests:
those made with a project-scoped API key, or that name the project with the X-NuRoute-Project-ID header. Unset
fields fall through to the organization: speed: null, an empty providerOrder or providerAffinity, and
weightsJson: ''. speed is Artemis Task's Speed setting. weightsJson holds the
balanced weights, which rank the providers of a model you name, and the choice fallback-router:apollo makes inside
its tier when Artemis Task cannot decide; Artemis Task does not read them.
setConfig() keeps every field you leave out, so you can send only your change. If the stored config cannot be read
at that moment, a call that leaves a field out fails with 503 and saves nothing. A project without a config of its
own reads back the defaults, not the organization's settings.
const current = await proj.routing.getConfig();
await proj.routing.setConfig({
...current,
strategy: 'cheapest',
speed: 'faster', // 'off' | 'faster' | 'fastest', or null to follow the organization
});
// Per-project model aliases
await proj.routing.setAliases({ smart: 'gpt-4o-mini' });
await proj.routing.deleteAlias('smart');
Policy
The policy applies to every request of the project: see
Policy enforcement. set() replaces the whole policy, so a field you
leave out is cleared; start from get().
const policy = await proj.policy.get();
await proj.policy.set({
...policy,
maxTokens: 4096,
allowedModels: ['gpt-4o', 'gpt-4o-mini'],
});
Budget
set() replaces the whole budget: send all three fields, since a missing hardLimit turns the hard limit off. See
Budget enforcement.
await proj.budget.set({
monthlyUsd: 500, // monthly cap, per calendar month (UTC)
alertPct: 80, // stored; budget alerts are not sent yet
hardLimit: true, // refuse the project's requests (402 budget_exceeded) once the cap is spent
});
const budget = await proj.budget.get();
console.log(budget.currentSpend, budget.monthlyUsd);
Environments
const { environments } = await proj.environments.list();
const { id } = await proj.environments.create({
name: 'Staging',
slug: 'staging',
isProduction: false,
});
await proj.environments.delete(id);
Project usage
const overview = await proj.usage.overview(24); // last 24 h
const series = await proj.usage.series(168); // last 7 days
const breakdown = await proj.usage.breakdown(24);