Platform

Tenancy and end-user attribution

Label sessions, tasks, and usage with your own user IDs so you can filter and report per user.

Tag each turn with your own user ID, then filter sessions and break down usage per user. Your account is the tenant: everything you create belongs to it, and your API key can reach all of it. A userId is a label for reporting, not a lock, so your backend keeps deciding who may see what.

Label a turn and filter by user

Pass userId and optional metadata when you call the agent. Later, pass the same userId as a filter. Set AGENT_ID to an agent with a provider and model, such as the one from the quickstart.

import { BlazingAgents } from "@blazingagents/sdk";

const client = new BlazingAgents({
  apiKey: process.env.BLAZING_AGENTS_API_KEY!,
});
const agentId = process.env.AGENT_ID!;
const userId = "app:user-42";

const result = await client.chat({
  agentId,
  message: {
    id: crypto.randomUUID(),
    role: "user",
    parts: [{ type: "text", text: "Summarize my open items." }],
  },
  userId,
  metadata: { plan: "pro" },
});
const sessionId = await result.sessionId;
await result.toResponse().text();

const sessions = await client.sessions.list({ agentId, userId });
console.log(sessions.data.some((session) => session.id === sessionId));

const usage = await client.usage.get({ userId, groupBy: "day" });
console.log(usage.totals.inputTokens + usage.totals.outputTokens);

The first line prints true: the new session carries the user's label. The second prints the tokens this user used over the last 30 days, the default usage window.

What carries a user label

Agents, workspaces, prompts, sessions, tasks, task runs, artifacts, memories, and usage records all accept userId and metadata. A skill takes its agent's label. Account-wide settings such as API keys, providers, and quotas have no user label.

Labels flow to the work they produce:

  • A session takes the userId and metadata of its first turn, and that turn's usage record gets the same values.
  • A task run takes its task's label, and so do the run's session, usage, and artifacts.
  • An artifact saved during a chat takes the session's label.

Once set, a userId never changes. Some resources let you update metadata later.

Filter and report

Session lists, task lists, and usage queries accept a userId filter. Usage can also be grouped by user, and the usage overview ranks your top users. See usage and quotas.

The filter has three modes:

  • Omit userId to include everything in your account.
  • Pass userId: "" to select only activity with no user label.
  • Pass any other value to select that exact user.

If you forget to pass userId, the activity is recorded with the empty label. Decide whether that is acceptable, or require a user ID in your backend.

A label is not access control

A userId does not prove who someone is, and it does not narrow what your API key can reach. Blazing Agents does not store your users or check their permissions. An empty filtered list does not mean a caller is barred from a resource ID they supply some other way.

Your backend must sign in the user, check that they own the chat or resource, and only then call Blazing Agents with IDs from its own storage.

Multi-tenant application pattern

When your product serves many customers, derive every ID on the server:

import { type UIMessage } from "@blazingagents/sdk";
import { client } from "./client.ts";
import * as app from "./app.ts";

export async function runAuthorizedTurn(
  principal: app.Principal,
  appChatId: string,
  message: UIMessage,
) {
  const chat = await app.resolveAuthorizedChat(principal, appChatId);
  const result = await client.chat({
    agentId: chat.agentId,
    ...(chat.sessionId ? { sessionId: chat.sessionId } : {}),
    message,
    userId: `app:${principal.subject}`,
    metadata: { organizationId: principal.organizationId },
  });
  if (!chat.sessionId) {
    await app.saveAuthorizedSession(appChatId, await result.sessionId);
  }
  return result.toResponse();
}

app is your own code. resolveAuthorizedChat throws unless the signed-in principal owns the chat, and it returns the agent and session IDs from your database. Test that one user cannot reach another user's chat ID before any Blazing Agents call happens.

Production notes

  • Use a stable, opaque userId such as app:<internal id>. Keep the mapping to real people in your own system.
  • Treat metadata as product data. Keep personal information out of it where you can, and validate it in your backend.
  • Check ownership before you read, resume, update, or delete any resource. A matching filter is not an authorization check.

Next

On this page