Banata

Start Here

Quick Start

Create your first sandbox, wait for readiness, send work to the AI agent, watch the browser, and get outputs back through the SDK.

This page shows the fastest complete integration path.

By the end of it, you will know how to:

  • create a client
  • launch a sandbox
  • wait for it to be usable
  • send work to the AI agent
  • watch the browser
  • collect files or artifacts
  • clean up when the job is done

1. Install the SDK

bash
npm install @banata-boxes/sdk

2. Create a client

ts
import { BanataSandbox } from "@banata-boxes/sdk";
 
const banata = new BanataSandbox({
  apiKey: process.env.BANATA_API_KEY!,
  baseUrl: "https://api.boxes.banata.dev",
});

This client is your entry point for:

  • sandbox lifecycle
  • agent tasks
  • browser preview links
  • file access
  • artifacts
  • webhooks
  • billing and usage reads

3. Launch a sandbox

For a first integration, use launch().

launch() is the easiest starting point because it:

  • creates the sandbox
  • waits for readiness
  • returns a session object that already targets that sandbox

If you want to use the AI agent, you should pass model provider settings in env when you create the sandbox.

Use:

  • OPENROUTER_API_KEY
  • OPENROUTER_MODEL

Recommended:

  • OPENROUTER_SMALL_MODEL

Without those values, the sandbox can still be created, but AI agent prompts may not do useful work.

ts
const sandbox = await banata.launch({
  env: {
    OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY!,
    OPENROUTER_MODEL: "openai/gpt-5.3-codex",
    OPENROUTER_SMALL_MODEL: "openai/gpt-5.3-codex",
  },
  capabilities: {
    agent: { enabled: true, defaultAgent: "build" },
    browser: {
      viewport: { width: 1440, height: 900 },
    },
    documents: { libreofficeHeadless: true },
  },
});
 
console.log("sandbox:", sandbox.sessionId);

What these values do:

  • OPENROUTER_API_KEY gives the agent access to the model provider
  • OPENROUTER_MODEL chooses the main model for the run
  • OPENROUTER_SMALL_MODEL gives the agent a lighter model for smaller decisions

Use launch() when:

  • you want to get productive quickly
  • your app does not need custom readiness orchestration
  • you want one method that returns a usable sandbox

Use create() when:

  • your own backend already has a job queue
  • you want to create first and wait later
  • you want more control over when the caller blocks

4. Check the browser preview

ts
const previewUrl = await sandbox.getPreviewViewerUrl();
console.log(previewUrl);

Use the preview when you want to:

  • watch the AI agent work
  • inspect browser state during debugging
  • let a person take over later

5. Run one direct command

Before sending an agent task, verify the sandbox itself is healthy.

ts
const result = await sandbox.exec("sh", ["-lc", "echo hello from banata"]);
console.log(result.stdout);

This is the fastest way to confirm:

  • the sandbox is live
  • commands run successfully
  • your client is authenticated correctly

6. Send a real AI agent task

For meaningful work, prefer promptAsync().

ts
const queued = await sandbox.promptAsync(
  "Open https://example.com, confirm the title, write TITLE:<title> to /workspace/result.txt, and reply briefly when done.",
  {
    metadata: {
      userId: "user_123",
      jobId: "job_456",
      source: "my-app",
    },
  },
);
 
console.log("task:", queued.taskId);

Why promptAsync() is the better default:

  • it returns quickly
  • it works well for long-running jobs
  • it gives you a taskId
  • it lets you attach your own metadata
  • it works naturally with webhooks

Use prompt() only when you truly want a short convenience call and you expect a quick reply.

7. Check task status

ts
const task = await sandbox.getAgentTask(queued.taskId!);
console.log(task?.status);

Task states you should expect:

  • queued
  • running
  • completed
  • failed

8. Use webhooks for production completion handling

Polling can work during development, but it is not the best pattern for production.

The better production flow is:

  1. call promptAsync()
  2. pass metadata that identifies the job in your system
  3. store taskId
  4. receive a webhook when the task finishes
  5. fetch files or artifacts afterward

That way:

  • your app does not hold one request open
  • you do not need constant polling
  • your webhook payload already tells you which job finished

9. Read files from /workspace

Small outputs are easiest to read directly.

ts
const text = await sandbox.fs.read("/workspace/result.txt");
console.log(text);

Use direct file reads when:

  • the file is small
  • you want the contents immediately
  • the file is mainly a working output, not a durable customer download

10. Use artifacts for durable outputs

ts
const artifactState = await sandbox.getArtifacts();
console.log(artifactState.artifacts);

Then, if you need a download URL:

ts
const item = artifactState.artifacts?.items?.[0];
if (item?.key) {
  const download = await sandbox.getArtifactDownloadUrl(item.key);
  console.log(download.url);
}

Artifacts are the better choice when:

  • the output is large
  • another system needs a stable file handoff
  • the output should remain associated with the sandbox as a durable result

11. End the sandbox

ts
await sandbox.kill();

End the sandbox when:

  • the job is complete
  • you already collected the outputs you need
  • you do not plan to resume later

Use pause() instead when the work should continue later and you want to keep the workspace around.

If you are integrating Banata into another product, this is the cleanest first design:

  1. create or launch a sandbox
  2. queue work with promptAsync()
  3. attach your own metadata
  4. let the agent save its outputs to /workspace
  5. receive completion through a webhook
  6. download final outputs through artifacts or direct file reads
  7. end the sandbox

That gives you:

  • stable async behavior
  • clean job tracking
  • clear ownership of outputs
  • a straightforward operational model

Next