Experimental · BYOK · TypeScript

Usage limits for your users.
3 lines of code.

Add usage limits for your users with almost no extra code — a drop-in OpenAI client metered against Devic's tenant/subtenant limits engine, tokens and cost, tranche by tranche.

$ npm install @devicai/model-gateway-sdk openai Get started
From plain OpenAI to per-user limits — click to see the code
plain-openai.ts
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const chat = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'Hello!' }],
});

console.log(chat.choices[0].message.content);
Tenants & subtenants

One list, every caller

Every tenantId you send is auto-provisioned on first use — no separate "create tenant" call. Subtenants nest underneath for per-end-user limits without building a new hierarchy.

  • Auto-provisioned on the first request that references it — sync or async, your choice.
  • Domain & logo inferred from the email in tenantMetadata, filled in once and never overwritten.
  • Subtenants scope limits to one end-user inside a tenant, same RuleUsage shape throughout.
tenants
4 tenants
AC
Acme Corp
acme.com · 3 subtenants
Enterprise
42%
user-48212%
user-1904%
+ 1 more subtenant
NW
Northwind Labs
northwind.io
Limited
88%
DT
demo-tenant
no domain detected
Free
3%
tenant · northwind-labs
NW
Northwind Labs
northwind.io
Tier
Free Limited Enterprise Custom
Ad-hoc overrides
+50,000 tokens · this month tenant
Cost cap raised to €80 · this month tenant
Tenant control

Presets when you want them, overrides when you don't

Assign a tier and move on, or layer a temporary rule on top without touching it — a Black Friday token bump, a one-off cost cap raise, scoped to a tenant or narrowed to a single subtenant.

  • Tier presets or ad-hoc overrides — both read through the same checkLimits call, no separate code path.
  • Real-time counters in Redis, durable configuration in Mongo — checks stay fast, config survives restarts.
  • Every override is scoped: tenant-wide, or narrowed to one subtenant.
Limits

Combine tranches — tokens and €, side by side

Mix as many rules as you need, freely combining metric and window — a fast 5-hour token burst limit alongside a monthly € budget, per tenant or per subtenant. The first rule a request would break wins; every other rule keeps counting in the background.

acme-corp · usage
MetricWindowUsageOriginResets
Tk tokens
1× hour (rolling 5h) 82,340 / 100,000
tier 38m
Tk tokens
1× month 612,000 / 1,000,000
tier 12d
cost
1× day €3.20 / €5.00
tier 9h
cost
1× month €61.40 / €150.00
ad-hoc 12d
Free
A safe default for anyone trying the SDK.
  • Tk 100,000 tokens / month
  • €0 — hard stop at quota
Limited
Token burst control plus a monthly budget.
  • Tk 100,000 tokens / 5h
  • Tk 1,000,000 tokens / month
  • €50 / month
Enterprise
Any combination of tranches, per tenant or subtenant.
  • custom tokens + € tranches
  • ad-hoc overrides layered on top

Read it inline

Every response carries the fresh percentage for every rule that applies.
const chat = await client.chat.completions.create({ ... });

chat.devic?.usage;
// [{ metric: 'tokens', windowUnit: 'hour', windowEvery: 5,
//    limit: 100000, current: 82340, percent: 82.3, resetsAt }, …]

Or query it yourself

The same data is one authenticated GET away — no SDK required.
const res = await fetch(
  'https://api.devic.ai/api/v1/tenant-usage/acme-corp',
  { headers: { Authorization: `Bearer ${DEVIC_API_KEY}` } },
);
const { data } = await res.json();
data.usage; // same RuleUsage[] as chat.devic.usage
How it works

Same client, one honest middleman

OpenAIClient extends the official OpenAI class from the openai package. It only overrides baseURL and defaultHeaders — every resource stays the untouched implementation from the SDK you already know.

BYOK passthrough

Your OpenAI key is still yours. It's forwarded to OpenAI on every request exactly as-is — the gateway never stores it, only meters the traffic passing through.

apiKey: process.env.OPENAI_API_KEY

Devic's real engine

tenantId/subtenantId plug into the same limits and cost-tracking engine that powers Devic's own assistants and agents in production — not a toy limiter.

tenantId: 'acme-corp'

Multi-provider ready

OpenAIClient is the first client this package exports. Anthropic, Gemini and others will share the same metering and error contract as they're added.

import { OpenAIClient } from '@devicai/model-gateway-sdk'
The basics

Nothing new to learn

Every method call is identical to the official SDK. What changes is what you get back and how limits surface — as a normal, catchable error.

Same interface as openai

Nothing to relearn — chat.completions, embeddings, responses… all untouched.
// exactly the same call as the official SDK
const chat = await client.chat.completions.create({
  model: 'gpt-4o-mini',
  messages,
});

console.log(chat.choices[0].message.content);

Tenant auto-detection

Pass a name and email once — Devic infers the corporate domain and pulls a logo.
new OpenAIClient({
  apiKey, devicApiKey,
  tenantId: 'acme-corp',
  tenantMetadata: {
    name: 'Acme Corp',
    email: 'ops@acme.com',
  },
});

Handling the 429

A tenant over its limit throws a normal APIError, narrowed for you.
try {
  await client.chat.completions.create({ ... });
} catch (err) {
  if (isTenantLimitExceeded(err)) {
    const { current, limit, resetsAt } = err.error.details;
    // "you're at 1,000,000/1,000,000 tokens, resets in 4h"
  }
  throw err;
}

No tenant, no problem

Leave tenantId out — still a valid BYOK passthrough, nothing metered.
new OpenAIClient({
  apiKey: process.env.OPENAI_API_KEY,
  devicApiKey: process.env.DEVIC_API_KEY,
  // no tenantId → pure passthrough,
  // no limits checked, nothing recorded
});