AI2IN AgentDesk API — per-scenario guide
The AI Workforce as a web service. You submit a case to a governed agent vertical; the agent works it end-to-end while every action is isolated, PII-masked, egress-controlled, and written to a tamper-evident ledger. Base URL: https://api.ai2in.dev. Auth: Authorization: Bearer ai2in_... (except the two public discovery routes). India-resident (Mumbai ap-south-1).
Two execution modes (this is the key thing to understand)
| Simulated run (default, today) | Live run (Claude-powered) | |
|---|---|---|
| Endpoint | POST /v1/agentdesk/verticals/{id}/runs (async) | POST /v1/agentdesk/run (SSE stream) |
| Brain | deterministic governed pipeline | claude-opus-4-8, real tool-use loop |
| Sandbox | steps recorded as sandbox.* ledger events | a real gVisor sandbox is opened and code runs in it |
| Needs | just an ai2in_ key | ai2in_ key + ANTHROPIC_API_KEY on the engine |
Both write to the same real, hash-chained agent_actions ledger. Use simulated for reliable, free integration + audit trails; use live for genuine reasoning.
When a real sandbox opens, and what runs in it
A real sandbox is opened only in a live run, the moment the agent calls the run_python tool — e.g. to compute a fraud/risk score (KYC) or run diagnostics and a fix (IT). The engine does exactly this (server/src/agentdesk.js):
// inside the run_python tool handler
if (!sandboxId) {
// 1) open an isolated gVisor sandbox on the node (no internet, runsc runtime)
const sbx = await createSandbox({}, 'ai2in/sandbox:python-3.12',
{ teamId, timeoutMs: 120000, metadata: { agentdesk: caseData.id } });
sandboxId = sbx.id;
}
// 2) run the agent's code inside it
const res = await runCode(sandboxId, input.code);
// 3) record the activity to the tamper-evident ledger (PII-safe)
recordAction({ teamId, alias, action: 'sandbox.run',
summary: 'ran risk/duplicate check in gVisor sandbox',
detail: { code: input.code.slice(0,300), stdout: String(res.stdout).slice(0,300) } });
// ...at the end of the run, the sandbox is torn down:
await deleteSandbox(sandboxId);So the lifecycle is: agent decides code is needed → createSandbox (open) → runCode (activity) → recordAction (audit) → deleteSandbox (teardown). The sandbox is per-run, isolated with gVisor, has no outbound internet, and every command it runs is in the ledger. In a simulated run the same step appears as a sandbox.run ledger entry (governed + audited) without spinning a container — so you can integrate and demo the audit trail before enabling live mode.
The call pattern (same for every vertical)
KEY="ai2in_YOUR_KEY"; V="kyc" # or it | support | voice
# 1) submit the case -> a run (202). Omit --data to use the built-in sample case.
RUN=$(curl -s -X POST "https://api.ai2in.dev/v1/agentdesk/verticals/$V/runs" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
--data '{"case": { "...": "your fields" }}')
ID=$(echo "$RUN" | jq -r .id)
# 2) poll until status is terminal (succeeded | error)
curl -s "https://api.ai2in.dev/v1/agentdesk/runs/$ID" -H "Authorization: Bearer $KEY"
# 3) pull the tamper-evident audit trail for this run
curl -s "https://api.ai2in.dev/v1/agentdesk/runs/$ID/ledger" -H "Authorization: Bearer $KEY"Node (any HTTP client works — no SDK required):
const H = { Authorization: `Bearer ${process.env.AI2IN_KEY}`, "Content-Type": "application/json" };
const base = "https://api.ai2in.dev/v1/agentdesk";
const run = await (await fetch(`${base}/verticals/it/runs`, { method: "POST", headers: H,
body: JSON.stringify({ case: { id: "INC-5012", host: "prod-api-01", severity: "P1" } }) })).json();
let s; do { await new Promise(r => setTimeout(r, 500));
s = await (await fetch(`${base}/runs/${run.id}`, { headers: H })).json();
} while (s.status === "running");
const ledger = await (await fetch(`${base}/runs/${run.id}/ledger`, { headers: H })).json();
console.log(s.decision, ledger.entries.length, "audited steps");Discovery (public, no key):
curl -s https://api.ai2in.dev/v1/agentdesk/verticals # list the 4 services
curl -s https://api.ai2in.dev/v1/agentdesk/openapi.json # full OpenAPI 3.1 contract1) kyc — Back-office automation (insurance claims / KYC)
Job: adjudicate a health-insurance claim from documents to decision.
curl -s -X POST https://api.ai2in.dev/v1/agentdesk/verticals/kyc/runs \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
--data '{"case":{"id":"CLM-2026-04417","applicant":"Ananya Sharma","pan":"ABCPS1234K","aadhaar":"234123456786","policy":"HLT-88213","amount":"₹1,84,500"}}'Flow (8 governed steps):
| # | action | what happens | governance |
|---|---|---|---|
| 1 | fs.read | OCR the claim form + discharge summary | — |
| 2 | pii.scan | detect PAN / Aadhaar / phone | masked in every log & the ledger |
| 3 | kyc.verify | PAN format + Aadhaar Verhoeff checksum | PII-tagged |
| 4 | db.query | confirm policy active & in-network | — |
| 5 | risk.score | → opens a sandbox and runs the duplicate/risk model | sandbox.run audited |
| 6 | egress.block | agent tries a 3rd-party enrichment API | blocked (not allow-listed) |
| 7 | agent.decision | adjudicate (approve / escalate) | recorded |
| 8 | db.write | file the case, queue payout | — |
Sandbox moment: step 5. The agent writes a short Python check and calls run_python → the engine opens a gVisor sandbox, runs it (no internet), records sandbox.run, and tears it down at the end.
2) it — IT helpdesk & ops
Job: diagnose and fix a production incident. This vertical is the heaviest sandbox user — the agent does real ops work, and every command is isolated.
curl -s -X POST https://api.ai2in.dev/v1/agentdesk/verticals/it/runs \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
--data '{"case":{"id":"INC-4471","host":"prod-web-03","severity":"P1","symptom":"502s, health check failing"}}'Flow (8 governed steps):
| # | action | what happens | governance |
|---|---|---|---|
| 1 | ticket.triage | classify P1, form a hypothesis | — |
| 2 | sandbox.open | opens a gVisor session scoped to the host — no host access | sandbox.open audited |
| 3 | sandbox.run | runs diagnostics (df -h, journalctl) in the sandbox | audited |
| 4 | agent.finding | root cause: access.log filled the disk | — |
| 5 | egress.block | agent tries to fetch a remediation script | blocked |
| 6 | sandbox.run | applies the fix (rotate/truncate logs, restart nginx) in the sandbox | audited |
| 7 | sandbox.run | verifies recovery (disk 41%, health 200) in the sandbox | audited |
| 8 | db.write | close the ticket with the full command trail | — |
Sandbox moments: steps 2–3 and 6–7. The agent opens one isolated session and runs diagnostics → fix → verify inside it. Because it's gVisor with no egress, a compromised or hallucinated command cannot touch the host or the network — and the entire command history is in the tamper-evident ledger.
3) support — Customer support
Job: resolve a support ticket on real customer data it can't leak. Data-centric — no sandbox needed (lookups + writes, not code execution).
curl -s -X POST https://api.ai2in.dev/v1/agentdesk/verticals/support/runs \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
--data '{"case":{"id":"TKT-90218","customer":"Rahul Verma","pan":"AAKPV9021M","account":"SB-2291-8830","issue":"Locked out"}}'Flow (7 governed steps):
| # | action | what happens | governance |
|---|---|---|---|
| 1 | ticket.read | parse intent (unlock + explain logins) | — |
| 2 | kyc.verify | match PAN + email on file | PII masked |
| 3 | db.query | look up account (3 failed logins, new device) | — |
| 4 | agent.finding | assess: benign lockout, reset approved | — |
| 5 | egress.block | agent tries a device-reputation API | blocked |
| 6 | db.write | reset access, send device alert | — |
| 7 | db.write | close ticket with masked trail | — |
Sandbox moment: none by default — the work is database reads/writes. If a policy required running code (e.g. a custom eligibility script), the agent would open a sandbox exactly as in KYC/IT; support simply doesn't need one.
4) voice — Voice call center (preview)
Job: handle an inbound call — verify, answer, update records. The speech layer (STT/TTS/telephony) sits on top of the same governed runtime; the agent logic here is DB-centric, no sandbox by default.
curl -s -X POST https://api.ai2in.dev/v1/agentdesk/verticals/voice/runs \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
--data '{"case":{"id":"CALL-7793","caller":"Meera Nair","phone":"+91 90031 22140","policy":"MOT-55110"}}'Flow (6 governed steps):
| # | action | what happens | governance |
|---|---|---|---|
| 1 | call.start | inbound call routed to the AI voice agent | — |
| 2 | kyc.verify | verify caller via phone + OTP | phone masked |
| 3 | db.query | answer: policy status | — |
| 4 | db.write | update the caller's address (read back + confirm) | — |
| 5 | egress.block | agent tries a maps autocomplete API | blocked |
| 6 | agent.decision | wrap up, send SMS confirmation | — |
Sandbox moment: none by default. Voice is I/O + DB; the isolation guarantees still apply to any tool the agent calls, and the whole call is in the ledger.
Verifying the audit trail
Every run's steps are appended to your team's agent_actions chain. Prove integrity independently (or from the dashboard's Governance console):
select * from verify_agent_ledger('<your-team-id>');
-- ok=true, checked=<n> ... or the first row where the chain was brokenGET /v1/agentdesk/runs/{id}/ledger returns that run's entries with row_hash / prev_hash, correlated by the run's ledger_ref.