Skip to content

Getting Started

Build a verified agent on Telbox — a cryptographically-identified participant that lives inside an end-to-end-encrypted messenger, reacts to messages and schedules, and acts only within the authority you grant it. This quickstart takes you from an API key to a real agent you've previewed, test-run, and inspected — using the REST API directly or the official Python / TypeScript SDKs.

Gated until launch

The external API-key auth path is gated behind the apikey_auth_enabled flag and is off in production until launch. Today these endpoints are reachable with a developer session JWT (the same one the developer console mints over email + OTP); once the flag flips, the tb_live_… / tb_test_… keys below authenticate external callers directly. The SDK snippets are written against the post-launch key flow — point the client's base URL at your developer preview until then.

What you'll build

An agent is a typed plan, not a free-form prompt. You give it:

  • a persona (its standing instructions),
  • one or more triggers — a schedule (cron), an inbound message, or a manual run,
  • a sequence of steps, each calling a tool from the live registry, and
  • guards that set each tool's authority level — the autonomy leash.

When you create an agent, Telbox mints it an Ed25519 identity (you'll see its identity_fingerprint on every read) so recipients can verify who's acting. Authority defaults to the cautious end: an agent drafts rather than acts unless you explicitly grant more, and external or irreversible tools never auto-act. See Agents and Authority for the full model.

1. Get an API key

Sign in to the developer console at https://developers.telbox.ai and create a key, or mint one programmatically. The raw key is returned exactly once — stash it immediately.

curl -X POST https://api.telbox.ai/v1/agents/api-keys \
  -H "Authorization: Bearer $TELBOX_SESSION_JWT"
201 Created
{
  "raw_key": "tb_test_9f3c…",
  "prefix": "tb_test_9f3c",
  "name": "developer-portal key",
  "scopes": ["threads:read", "messages:write", "voice_notes:write"],
  "env": "test"
}
from telbox import TelboxClient

tb = TelboxClient(api_key="tb_live_…", base_url="https://api.telbox.ai")
issued = tb.create_api_key()
print(issued.raw_key)   # shown once — stash it now
import { TelboxClient } from "@telbox/sdk";

const tb = new TelboxClient({ apiKey: "tb_live_…", baseUrl: "https://api.telbox.ai" });
const issued = await tb.createApiKey();
console.log(issued.rawKey);   // shown once — stash it now

A self-serve key gets the default scopes threads:read, messages:write, and voice_notes:write. The env is live in production and test elsewhere. Broader scopes (messages:read.raw, webhooks, SCIM) stay opt-in — see Authentication.

Install the SDK

pip install telbox
npm install @telbox/sdk

2. Base URL & auth

Every request goes to the production host and carries your key as a Bearer token:

https://api.telbox.ai
curl https://api.telbox.ai/v1/agents \
  -H "Authorization: Bearer tb_live_…"

The Agents endpoints live under /v1 (/v1/agents, /v1/agent-templates, /v1/agent-tools). The SDK clients default to this host; override with base_url (Python) / baseUrl (TypeScript) to hit a developer preview.

3. The full loop

The end-to-end flow is: create an agent (install a template, or build it from an IR) → dry-run it (deterministic preview, no LLM, no side effects) → test-run it (a real run in a safe sandbox) → read the runs to see what happened.

Step 1 — Create an agent

Either install a curated template by id, or post a typed AgentDefinitionIR. Both return an AgentDetail (its id, slug, identity_fingerprint, tools, triggers, ir, and more).

# Browse the catalog
curl https://api.telbox.ai/v1/agent-templates \
  -H "Authorization: Bearer tb_live_…"

# Option A — install a template
curl -X POST https://api.telbox.ai/v1/agents/from-template \
  -H "Authorization: Bearer tb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "vip-watcher" }'

# Option B — create from an Intermediate Representation
curl -X POST https://api.telbox.ai/v1/agents \
  -H "Authorization: Bearer tb_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nudge non-repliers",
    "persona": "Each Monday, nudge whoever still owes a reply — gently.",
    "triggers": [{ "kind": "schedule", "cron": "0 9 * * 1" }],
    "steps": [
      { "id": "s1", "tool": "get_tasks", "args": { "status": { "literal": "open" } } },
      { "id": "s2", "tool": "create_reminder", "args": { "title": { "prompt": "follow up" } } }
    ],
    "guards": { "reminders": { "authority": "auto_act_limited" } }
  }'
from telbox import TelboxClient, ir

tb = TelboxClient(api_key="tb_live_…")

# Option A — install a template
agent = tb.install_template("vip-watcher")

# Option B — build from a typed IR
agent = tb.create_agent(ir.agent(
    "Nudge non-repliers",
    persona="Each Monday, nudge whoever still owes a reply — gently.",
    triggers=[ir.schedule("0 9 * * 1")],
    steps=[
        ir.tool("s1", "get_tasks", status=ir.literal("open")),
        ir.tool("s2", "create_reminder", title=ir.prompt("follow up")),
    ],
    guards={"reminders": ir.guard("auto_act_limited")},
))
print(agent.id, agent.identity_fingerprint)
import { TelboxClient, ir } from "@telbox/sdk";

const tb = new TelboxClient({ apiKey: "tb_live_…" });

// Option A — install a template
let agent = await tb.installTemplate("vip-watcher");

// Option B — build from a typed IR
agent = await tb.createAgent(ir.agent("Nudge non-repliers", {
  persona: "Each Monday, nudge whoever still owes a reply — gently.",
  triggers: [ir.schedule("0 9 * * 1")],
  steps: [
    ir.tool("s1", "get_tasks", { status: ir.literal("open") }),
    ir.tool("s2", "create_reminder", { title: ir.prompt("follow up") }),
  ],
  guards: { reminders: ir.guard("auto_act_limited") },
}));
console.log(agent.id, agent.identityFingerprint);

Not sure where each argument comes from?

IR argument bindings declare each tool argument's source: literal (a fixed value), from_trigger (a value from the firing event), from_step (a value from an earlier step's result), or prompt (let the agent decide from context). The full IR — triggers, guards, and authority levels — is covered in Agents.

Step 2 — Dry-run (deterministic preview)

A dry-run shows exactly what the agent would do — every step, each write's real authority decision, whether it'd auto-reply — with no LLM call and zero side effects. Run it on a draft IR before creating it, or on an installed agent.

curl -X POST https://api.telbox.ai/v1/agents/$AGENT_ID/dry-run \
  -H "Authorization: Bearer tb_live_…"
200 OK
{
  "name": "Nudge non-repliers",
  "triggers": ["schedule"],
  "steps": [ { "id": "s1", "tool": "get_tasks" }, { "id": "s2", "tool": "create_reminder" } ],
  "effects": { "reads": 1, "auto": 1 },
  "would_auto_reply": false,
  "warnings": []
}
preview = tb.dry_run_agent(agent.id)
print(preview.effects, preview.warnings)
const preview = await tb.dryRunAgent(agent.id);
console.log(preview.effects, preview.warnings);

To preview an IR you haven't created yet, post it to POST /v1/agents/dry-run (SDK: dry_run / dryRun).

Step 3 — Test-run (safe sandbox)

A test-run executes the agent once against a sample prompt and persists a durable AgentRun. It's a safe sandbox: write tools propose (mint a confirm token) but never auto-execute, so you can re-run without creating real tasks or reminders. A failed run (e.g. no model configured) is recorded with its error rather than failing the call.

curl -X POST https://api.telbox.ai/v1/agents/$AGENT_ID/test-run \
  -H "Authorization: Bearer tb_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "What'\''s open this week?" }'
201 Created
{
  "id": "9c21…",
  "status": "completed",
  "prompt": "What's open this week?",
  "latency_ms": 842,
  "model_used": "gemini-3.1-flash-lite",
  "error": null,
  "answer": "You have 3 open items…",
  "trace": [ { "kind": "tool", "…": "…" }, { "kind": "answer", "text": "…" } ]
}
run = tb.test_run(agent.id, "What's open this week?")
print(run.ok, run.answer)
for step in run.trace or []:
    print(step)   # tool args, results, errors, timing
const run = await tb.testRun(agent.id, "What's open this week?");
console.log(run.status, run.answer, run.trace);

Step 4 — Read the runs

Every run is durable. List an agent's run history, or fetch one run's full trace (the RunDetail adds the step trace and the final answer).

# History (newest first; paginate with ?limit= & ?offset=)
curl https://api.telbox.ai/v1/agents/$AGENT_ID/runs \
  -H "Authorization: Bearer tb_live_…"

# One run, with its full trace
curl https://api.telbox.ai/v1/agents/$AGENT_ID/runs/$RUN_ID \
  -H "Authorization: Bearer tb_live_…"
for r in tb.list_runs(agent.id):
    print(r.status, r.latency_ms, r.model_used)

detail = tb.get_run(agent.id, run.id)
print(detail.answer)
for (const r of await tb.listRuns(agent.id)) {
  console.log(r.status, r.latencyMs, r.modelUsed);
}

const detail = await tb.getRun(agent.id, run.id);
console.log(detail.answer);

Inspecting and revoking

GET /v1/agents/{id} returns the agent's IR, persisted persona, permissions, consent state, and identity fingerprint. DELETE /v1/agents/{id} revokes it — tombstoning the definition, revoking all grants, and disabling every trigger.

Next steps

  • Agents — the IR in full: triggers, steps, argument bindings, the tool registry, and identity.
  • Authority — the autonomy leash (disableddraft_onlyask_before_actionauto_act_limited), guards, grants, and how write/external tools are gated.
  • Python SDK — the complete TelboxClient reference, async client, error types, and retry behavior.