# Sandbox

Sandbox launches an isolated Chromium browser inside the TEE, allowing AI Agents to complete web automation tasks by sending operation instructions. **Credential plaintext is automatically injected in the TEE; Agents never touch passwords.**

## Complete Example: Bank Statement Download

The following example shows how an AI Agent logs into a bank and downloads statements through toani Vault:

```typescript
import { toaniVaultSDK } from '@toani/vault-sdk';

const sdk = toaniVaultSDK.create(baseUrl, token);

// 1. Create Sandbox session, bind credential
const session = await sdk.sandbox.createSession({
  serviceId: 'mybank',           // Must match credential Service ID
  credentialId: '018f1b4e-...',  // Bank credential created in console
  startUrl: 'https://www.mybank.com/login',
});
const sessionId = session.sessionId;

// 2. Navigate to login page
await sdk.sandbox.navigate(sessionId, 'https://www.mybank.com/login');

// 3. Fill form
//    TEE automatically replaces {{CREDENTIAL.xxx}} with real credential, Agent doesn't know password
await sdk.sandbox.fill(sessionId, '#username', '{{CREDENTIAL.username}}');
await sdk.sandbox.fill(sessionId, '#password', '{{CREDENTIAL.password}}');

// 4. Click login
await sdk.sandbox.click(sessionId, '#login-btn');

// 5. Wait for login completion
await sdk.sandbox.waitForSelector(sessionId, '.account-dashboard', {
  timeout: 10000,
});

// 6. Navigate to statements page
await sdk.sandbox.navigate(sessionId, 'https://www.mybank.com/statements');

// 7. Export structured data
const exported = await sdk.sandbox.exportData(sessionId, {
  format: 'json',
  selector: '.transaction-table',
  extractionRules: [
    { name: 'date',        selector: '.date' },
    { name: 'amount',      selector: '.amount' },
    { name: 'description', selector: '.desc' },
  ],
});

// 8. Take screenshot for record
const screenshot = await sdk.sandbox.takeScreenshot(sessionId, {
  fullPage: true,
  type: 'png',
});

// 9. Close session, release resources
await sdk.sandbox.closeSession(sessionId);

// 10. Return results to Agent (no plaintext credentials)
return {
  transactions: exported.data,
  screenshot: screenshot.imageData, // Base64 PNG
};
```

## Credential Placeholders

In the `value` parameter of `fill` operations, use `{{CREDENTIAL.fieldname}}` to reference credential plaintext:

| Credential Type       | Available Placeholders                                                            |
| --------------------- | --------------------------------------------------------------------------------- |
| `username_password`   | `{{CREDENTIAL.username}}`, `{{CREDENTIAL.password}}`                              |
| `api_key`             | `{{CREDENTIAL.key}}`, `{{CREDENTIAL.secret}}`                                     |
| `oauth_token`         | `{{CREDENTIAL.refresh_token}}`                                                    |
| `certificate`         | `{{CREDENTIAL.certificate}}`, `{{CREDENTIAL.private_key}}`                        |
| `ssh_key`             | `{{CREDENTIAL.ssh_key}}`                                                          |
| `database_connection` | `{{CREDENTIAL.host}}`, `{{CREDENTIAL.username}}`, `{{CREDENTIAL.password}}` etc.  |
| `zkme_credential`     | `{{CREDENTIAL.credential_json}}`, `{{CREDENTIAL.did}}`, `{{CREDENTIAL.zk_proof}}` |

Placeholders are replaced with plaintext inside the TEE enclave, at the moment the browser executes the operation; memory is then immediately zeroed.

## Supported Operations

| Method                                           | Description                                                 |
| ------------------------------------------------ | ----------------------------------------------------------- |
| `navigate(sessionId, url)`                       | Navigate to specified URL                                   |
| `click(sessionId, selector)`                     | Click element (CSS selector)                                |
| `fill(sessionId, selector, value)`               | Fill form field, supports `{{CREDENTIAL.xxx}}` placeholders |
| `getText(sessionId, selector)`                   | Get element text content                                    |
| `getAttribute(sessionId, selector, attr)`        | Get element attribute value                                 |
| `executeScript(sessionId, script)`               | Execute JavaScript, return result                           |
| `waitForSelector(sessionId, selector, options?)` | Wait for element to appear (timeout configurable)           |
| `takeScreenshot(sessionId, options?)`            | Full page or element screenshot, return Base64              |
| `exportData(sessionId, request)`                 | Extract structured data by rules                            |
| `pauseSession(sessionId)`                        | Pause session, keep browser state                           |
| `resumeSession(sessionId)`                       | Resume paused session                                       |
| `closeSession(sessionId)`                        | Close and clean up session                                  |

## Completing Third-Party Verification with a zkMe Credential

When a bank or exchange page requires identity or compliance verification, the agent can safely inject a zkMe-issued W3C VC into the page's verification widget via `executeScript` inside the TEE (zkKYC shown as example; zkPoAI accredited investor verification, AMLMe compliance checks, and other credential types follow the same pattern):

```typescript
import { toaniVaultSDK } from '@toani/vault-sdk';

const sdk = toaniVaultSDK.create(baseUrl, token);

// 1. Create Sandbox session bound to zkMe Credential
const session = await sdk.sandbox.createSession({
  serviceId: 'mybank',
  credentialId: 'zkme-cred-...',   // zkme_credential type credential created in console
  startUrl: 'https://www.mybank.com/kyc',
});
const sessionId = session.sessionId;

// 2. Navigate to bank verification page
await sdk.sandbox.navigate(sessionId, 'https://www.mybank.com/kyc');

// 3. Decrypt zkMe Credential in TEE and inject W3C VC into page widget
//    The agent never touches the raw identity or financial data in credential_json
await sdk.sandbox.executeScript(
  sessionId,
  `window.zkMeWidget.submitCredential({{CREDENTIAL.credential_json}})`
);

// 4. Wait for verification result
await sdk.sandbox.waitForSelector(sessionId, '.kyc-approved', {
  timeout: 15000,
});

// 5. Screenshot
const screenshot = await sdk.sandbox.takeScreenshot(sessionId, {
  fullPage: true,
  type: 'png',
});

// 6. Close session
await sdk.sandbox.closeSession(sessionId);

// 7. Return result to agent — no raw identity or financial data
return {
  verifyStatus: 'approved',
  screenshot: screenshot.imageData,
};
```

**Security property**: the full W3C VC in `credential_json` is only decrypted and injected inside the TEE enclave. The agent receives only `verifyStatus: 'approved'`.

> **Note**: `window.zkMeWidget.submitCredential` is an illustrative interface. Refer to the zkMe documentation for the current API. The same mechanism applies to zkPoAI accredited investor verification, AMLMe compliance checks, and all other zkMe Credential types.

## Credential Placeholders (continued)

For complete sandbox documentation and API details, see the [API Reference](/toani-vault/getting-started/api-reference.md).

## WebSocket Real-Time Monitoring (Optional)

Receive operation progress in real-time via WebSocket, suitable for showing execution status to users:

```typescript
import { SandboxWebSocketClient } from '@toani/vault-sdk';

const ws = new SandboxWebSocketClient({
  baseUrl: 'wss://vault.toani.ai',
  token: 'v4.local.your-token',
  sessionId: session.sessionId,
  credentialId: '018f1b4e-...',
});

ws.onOperationProgress = (data) => {
  console.log(`Progress: ${data.progress}% - ${data.message}`);
};

ws.onOperationCompleted = (data) => {
  console.log('Result:', data.result);
};

await ws.connect();

// Send operation instruction
await ws.executeOperation({
  operationType: 'navigate',
  description: 'Navigate to bank login page',
  parameters: { url: 'https://www.mybank.com/login' },
});
```

## Integration into Agent Frameworks

Wrap Sandbox as a LangChain / AutoGen Tool:

```typescript
import { toaniVaultSDK } from '@toani/vault-sdk';

const sdk = toaniVaultSDK.create(baseUrl, token);

const credBridgeTool = {
  name: 'toani_vault_browser',
  description: 'Execute web operations requiring login in TEE-secure environment, return data and screenshots',
  async call({ serviceId, credentialId, url, steps }: {
    serviceId: string;
    credentialId: string;
    url: string;
    steps: Array<{ action: string; selector?: string; value?: string }>;
  }) {
    const session = await sdk.sandbox.createSession({
      serviceId,
      credentialId,
      startUrl: url,
    });

    const results = [];
    for (const step of steps) {
      const result = await sdk.sandbox.executeOperation(session.sessionId, {
        operationType: step.action as any,
        selector: step.selector,
        value: step.value,
      });
      results.push(result);
    }

    const screenshot = await sdk.sandbox.takeScreenshot(session.sessionId);
    await sdk.sandbox.closeSession(session.sessionId);

    return { results, screenshot: screenshot.imageData };
  },
};
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.toani.ai/toani-vault/getting-started/sandbox.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
