APIZ guide
TypeScript SDK
Use @apiz/sdk in your trusted Node application. Provider sandboxes remain native
objects; agents inside them use CLI setup and their ordinary official SDKs.
Install
Use Node 22 or 24 (Node 24 recommended). Create your project and install from npm:
mkdir apiz-demo
cd apiz-demo
npm init -y
npm install @apiz/sdk [email protected]
The SDK ships ESM and TypeScript declarations. E2B is optional; to install only
the core SDK, run npm install @apiz/sdk. The .mjs tutorial runs directly with
Node; TypeScript projects use the same imports and get the package's types.
There is no CommonJS build or browser-management entrypoint.
Tutorial: E2B Host With An Official-Tool Guest
Configure an S3 API connection, read Policy and Client Binding in the Web Console.
Choose an existing allowed object. Create .env in your new project:
APIZ_USER_API_KEY=replace-with-your-user-api-key
APIZ_SERVER_URL=https://current-host
APIZ_TEAM_ID=replace-with-your-team-id
APIZ_CLIENT_ID=replace-with-your-client-id
E2B_API_KEY=replace-with-your-e2b-api-key
APIZ_EXAMPLE_BINDING=replace-with-your-s3-binding-alias
APIZ_EXAMPLE_OBJECT_KEY=demo/hello.txt
Replace the placeholders:
| Variable | Meaning |
|---|---|
APIZ_USER_API_KEY | Host-only User API Key with Team/Client issuance and revoke access |
APIZ_SERVER_URL | Reachable HTTPS Control Plane URL |
APIZ_TEAM_ID, APIZ_CLIENT_ID | Team and existing Client IDs |
E2B_API_KEY | Host-only E2B key |
APIZ_EXAMPLE_BINDING | S3 Binding alias |
APIZ_EXAMPLE_OBJECT_KEY | Allowed object key |
Save the following as main.mjs, then create the guest file described below.
Run node --env-file=.env main.mjs once both files exist. This creates a real E2B
sandbox. Exported variables override values in .env.
// Trusted host: the native E2B object stays under the caller's control.
import { readFile } from "node:fs/promises";
import { issueAccess } from "@apiz/sdk/access";
import { installCommand } from "@apiz/sdk/cli";
import { Management } from "@apiz/sdk/management";
import { Sandbox } from "e2b";
function required(name) {
const value = process.env[name];
if (!value) throw new Error(`Set ${name}`);
return value;
}
const api = new Management({
apiKey: required("APIZ_USER_API_KEY"),
serverUrl: required("APIZ_SERVER_URL"),
teamId: required("APIZ_TEAM_ID"),
});
const sandbox = await Sandbox.create({
apiKey: required("E2B_API_KEY"),
timeoutMs: 600_000,
});
try {
await sandbox.files.write(
"/home/user/guest_s3.py",
await readFile(new URL("./guest_s3.py", import.meta.url), "utf8"),
);
await sandbox.commands.run("python -m pip install boto3", {
timeoutMs: 120_000,
});
await sandbox.commands.run(installCommand({ serverUrl: api.serverUrl }), {
timeoutMs: 120_000,
});
const access = await issueAccess(api, {
clientId: required("APIZ_CLIENT_ID"),
ttlSeconds: 600,
env: {
APIZ_CLI_PATH: "/tmp/apiz/bin/apiz",
...Object.fromEntries(
["APIZ_EXAMPLE_BINDING", "APIZ_EXAMPLE_OBJECT_KEY"].map((name) => [
name,
required(name),
]),
),
},
});
await access.withAccess(async () => {
const result = await sandbox.commands.run("python /home/user/guest_s3.py", {
envs: access.exportEnv(),
timeoutMs: 30_000,
});
if (result.exitCode !== 0)
throw new Error("Guest request failed; inspect APIZ access logs");
});
await sandbox.commands.run("true");
console.log("PASS: access revoked; native sandbox remains usable");
} finally {
await sandbox.kill();
await api.close();
}
Create guest_s3.py beside main.mjs using the full code in the
guest tutorial. The guest is Python by
design: CLI setup and boto3 run independently of your host language. No Python
installation is needed on your host for this Node tutorial.
node --env-file=.env main.mjs
Success ends with PASS: access revoked; native sandbox remains usable. The host
then deletes the sandbox. Find the S3 request in Access Logs; CLI readiness
alone is not upstream acceptance. Credentials/setup output are not printed.
Case: Optional CLI Installation
import { installCommand } from "@apiz/sdk/cli";
const command = installCommand({
serverUrl: api.serverUrl,
installDir: "/tmp/apiz/bin",
runtime: "node",
});
await sandbox.commands.run(command, { timeoutMs: 120_000 });
installCommand is synchronous, performs no I/O and creates no credentials.
Choose "sh" (curl/wget, default), "python" (python3) or "node" (Node.js 22+).
All execute the same install.sh, requiring POSIX sh, tar and Unix utilities.
See CLI installation. Use /tmp/apiz/bin/apiz afterward
or configure PATH yourself; subsequent processes do not inherit an installation
command's PATH. Skip this step if your image already contains the CLI.
Case: Bring Your Own Sandbox Or Agent
Create the sandbox with native options for region, image, files and persistence.
Optionally execute installCommand({serverUrl: api.serverUrl}) with its native
command API, then call issueAccess(api, options). APIZ receives no sandbox object.
Replace the example guest command with your installed agent entrypoint, retaining
env: access.exportEnv() (E2B calls the option envs). Use an absolute CLI path
or set PATH explicitly in your own command; exportEnv supplies Client credentials.
Do not spread process.env into the guest. Customize the agent and its official
tools using CLI-generated setup for its Binding.
Case: Explicit Revocation
Inside an existing host scope with api, sandbox and clientId:
const access = await issueAccess(api, {
clientId,
ttlSeconds: 600,
});
try {
await sandbox.commands.run(
"/tmp/apiz/bin/apiz --output json client handoff inspect",
{ envs: access.exportEnv(), timeoutMs: 30_000 },
);
} finally {
const report = await access.revoke();
if (report.revocation === "unknown") {
console.error("Reconcile credential group", access.reference);
}
}
withAccess handles normal/exceptional callback completion and cleanup. Manual
revoke() returns a report which you must inspect. Repeated revocation calls
share the cached report; they are not retries. Neither mode deletes the sandbox.
Keep Management open until revocation finishes; api.close() only closes the
HTTP client state.
Case: Cancellation And Separate Time Budgets
const access = await issueAccess(api, {
clientId,
ttlSeconds: 600,
timeoutSeconds: 60,
cleanupTimeoutSeconds: 15,
signal: AbortSignal.timeout(90_000),
});
This fragment configures preparation; it does not run or automatically bound a later agent command. Pass the provider's native timeout/signal options to that command separately. Credential TTL, sandbox lifetime, preparation timeout and cleanup budget are independent. Aborting an HTTP mutation does not undo a server commit. Do not interpret cancellation as successful revocation.
Case: Management Without A Sandbox
Save this as management.mjs and run node --env-file=.env management.mjs.
Only the four APIZ management variables are needed; it makes no upstream call:
import {
CreationOutcomeUnknown,
CreationOutputUnavailable,
Management,
} from "@apiz/sdk/management";
const management = new Management({
apiKey: process.env.APIZ_USER_API_KEY,
serverUrl: process.env.APIZ_SERVER_URL,
teamId: process.env.APIZ_TEAM_ID,
});
try {
const prepared = management.credentials.prepare({
clientId: process.env.APIZ_CLIENT_ID,
ttlSeconds: 900,
allBindings: true,
label: "SDK example",
});
// Persist this safe ID before submission in a real orchestrator.
console.log("Creation operation:", prepared.operationId);
let issued;
try {
issued = await management.credentials.create(prepared);
} catch (error) {
if (error instanceof CreationOutcomeUnknown) {
const status = await management.creationOperations.get(
prepared.clientId,
prepared.operationId,
);
console.log("Creation state:", status.state);
if (status.state === "committed")
await management.credentials.revoke(status.credential_group_id);
// not_observed remains unknown; keep the operation ID for later lookup.
} else if (
error instanceof CreationOutputUnavailable &&
error.metadata.credential_group_id
) {
await management.credentials.revoke(error.metadata.credential_group_id);
}
throw error;
}
try {
console.log("Created group:", issued.credentialGroupId);
console.log("Expires at:", issued.expiresAt);
} finally {
await management.credentials.revoke(issued.credentialGroupId);
}
} finally {
await management.close();
}
Persist prepared.operationId before credentials.create(prepared). On
CreationOutcomeUnknown, query creationOperations.get(clientId, operationId);
not_observed remains unknown. A known committed group can be revoked explicitly.
For a custom executor, issueAccess(api, {clientId, ttlSeconds}) from
@apiz/sdk/access issues access without provider CLI installation. Your executor
owns preparation, just as it does when using any native provider SDK.
Management API Reference
Network methods return promises and accept options with timeoutMs and signal.
The default HTTP deadline is 30 seconds and covers response-body consumption.
| Method | Purpose |
|---|---|
clients.list() / clients.get(id) | Discover/read accessible Clients |
clients.bindings(id) / clients.setupOptions(id) | Inspect Client configuration |
credentials.prepare({clientId, ttlSeconds, allBindings: true}) | Allocate a local issuance operation |
credentials.create(prepared) | Issue sensitive credentials |
credentials.get(groupId) / credentials.revoke(groupId) | Read/revoke a group |
creationOperations.get(clientId, operationId) | Reconcile uncertain creation |
accessLogs.list({clientId, decision: "deny", limit: 20}) | Find denied requests |
accessLogs.request(requestId) | Retrieve correlated evidence |
This surface is not yet a complete wrapper for every APIZ management endpoint. User API Key scopes and current membership/role still apply.
Failure Handling
Import error types from @apiz/sdk/errors. ConfigurationError is a local input
failure; APIZError provides sanitized status/code/reason for server failures.
CreationOutcomeUnknown requires operation reconciliation. CleanupError means
normal callback work completed but automatic cleanup was not confirmed.
Use cleanupReport(error) and accessReference(error) from @apiz/sdk/access
to retrieve safe cleanup status and IDs. If the callback throws, its original
error is preserved with cleanup metadata. Access references are safe to persist;
credential values, setup manifests and exportEnv() are not safe log payloads.
Provider Guides
E2B, Daytona, Modal, and
Vercel each document native creation, command APIs, cleanup and
validation limits. @apiz/policy-sdk is a separate authoring package described
in the Policy SDK guide; it is not required to grant access.