AdminClient
How trusted environments manage products, issue user tokens, and maintain runtime env.
AdminClient should only run in trusted environments.
Typical cases:
- your own product backend
- local admin scripts
- internal tools
- CI or operations scripts
Do not expose admin_secret_key to browsers, public frontends, or uncontrolled clients.
Minimal example
import { AdminClient } from "@visiblebase/client";
const admin = new AdminClient({
base_url: "https://base.example.com",
admin_secret_key: process.env.VISIBLEBASE_ADMIN_SECRET_KEY,
});If admin_secret_key is omitted, the SDK tries to read process.env.VISIBLEBASE_ADMIN_SECRET_KEY.
Typical call chain
/api/admin/products, /api/admin/tokens/apply, and /api/admin/env.admin_secret_key, then executes product, token, and env management actions.products
list()
const items = await admin.products.list();create()
const product = await admin.products.create({
name: "Chrome Extension",
});The response includes:
product_idnamestatuscreated_atupdated_at
pause() / activate()
await admin.products.pause({
product_id: product.product_id,
});
await admin.products.activate({
product_id: product.product_id,
});Useful when you need to:
- stop all user calls for one product
- temporarily take a product offline
- reopen calls for a product later
remove()
await admin.products.remove({
product_id: product.product_id,
});The current behavior is direct product deletion. Confirm that this matches your business expectation before using it.
tokens.apply()
This is the most common trusted-side action: issue a user_token for one user under one product.
const issued = await admin.tokens.apply({
product_id: product.product_id,
user_id: "user_123",
metadata: {
plan: "pro",
org_id: "org_001",
},
ttl: "7d",
});The response includes:
user_tokenproduct_iduser_idexpires_at
ttl supports:
30m1h7d- raw seconds
Recommended login flow
router.post("/login", async (c) => {
const user_id = await login(c);
const issued = await admin.tokens.apply({
product_id: "prod_xxx",
user_id,
ttl: "7d",
});
return c.json({
product_id: "prod_xxx",
user_token: issued.user_token,
});
});That means:
- your backend handles user login first
- the trusted backend asks Base for
user_token - it returns
product_id + user_tokento the client - the client calls Base through
UserClient
env
admin.env manages runtime .env values.
list()
const envs = await admin.env.list();upsert()
await admin.env.upsert({
key: "OPENAI_API_KEY",
value: "sk-xxx",
});remove()
await admin.env.remove("OPENAI_API_KEY");import()
await admin.env.import(`
OPENAI_API_KEY=sk-xxx
OPENAI_BASE_URL=https://api.openai.com/v1
`);These changes are written back to the .env file currently used by Base.
Error handling
When AdminClient receives a non-2xx HTTP response, it throws an Error with two extra fields:
status: the HTTP status code.body: the raw response body from Base, usually{"error":"..."}.
try {
await admin.tokens.apply({
product_id: "prod_xxx",
user_id: "user_123",
});
} catch (error) {
const status = error instanceof Error && "status" in error ? error.status : undefined;
const body = error instanceof Error && "body" in error ? error.body : undefined;
console.log(status, body);
}Common statuses:
401:admin_secret_keyis missing or wrong.403: the target product is paused, so no token can be issued.404: the target product does not exist.500: Base is missing required config, or the admin action failed internally.
What AdminClient does not manage right now
These do not belong to AdminClient yet:
- model configuration
- direct edits to the
modelstable - service handler registration
Those belong to:
- the database layer
- the
Baseruntime layer