Getting Started with Anima in 5 Minutes

Create an agent identity, send an email from it, and place a voice call. A working Anima integration in roughly five minutes.

Diyan BogdanovDiyan Bogdanov3 min read
#tutorial#getting-started#sdk

If you can run a TypeScript script, you can launch your first agent communication workflow in minutes. This guide shows the fastest path: install the SDK, create an identity, send an email, and place a phone call. You will also see where to expand into SMS and vault-backed secrets when you are ready.

1) Install the SDK#

Create a small project or use an existing Node runtime. Add the Anima SDK:

bun add @anima-labs/sdk

Set your API key in environment variables:

export ANIMA_API_KEY="ak_..."

If you are building in a server app, place this key in your secrets manager and inject it at runtime. Do not expose it client-side.

2) Initialize the client and create an agent#

An agent is the actor boundary. Instead of one shared account for every automation, each agent gets its own identity, its own credentials, and its own policy.

import { Anima } from "@anima-labs/sdk";
 
const anima = new Anima({ apiKey: process.env.ANIMA_API_KEY! });
 
const agent = await anima.agents.create({
  orgId: process.env.ANIMA_ORG_ID!,
  name: "Support Triage Agent",
  slug: "support-triage-agent",
  provisionPhone: true,
  metadata: {
    environment: "sandbox",
    owner: "support-platform",
  },
});
 
console.log("Agent created:", agent.id);
console.log("Inbox:", agent.emailIdentities[0]?.email);

The agent gets an inbox on agents.useanima.sh automatically. provisionPhone asks for a number as well — that one needs a paid plan, since telephony starts on Starter.

In production, you can attach policy constraints to the agent itself: allowed and blocked recipient domains for email, per-hour send and SMS rate limits, allowed destination countries for phone and voice, and a switch that disables a channel outright. Spend is bounded separately, by your plan's quotas rather than by agent policy.

3) Send your first email#

Now that your agent exists, you can send mail as that agent. to is an array, and body is the plain-text part — bodyHtml is optional and additive, so a client that refuses HTML still has something to render:

await anima.messages.sendEmail({
  agentId: agent.id,
  to: ["customer@example.com"],
  subject: "Welcome to Anima",
  body: "You're live. Your agent channel is configured and ready.",
  bodyHtml: `<h1>You're live</h1><p>Your agent channel is configured and ready.</p>`,
});

If you are receiving inbound messages too, configure webhook delivery and verify signatures in your backend. This preserves a tamper-evident audit path for agent actions.

4) Place a phone or voice call#

Voice uses the same agent boundary. A minimal outbound call looks like this:

const call = await anima.calls.create({
  agentId: agent.id,
  to: "+15551234567",
  greeting: "Hello! This is your support assistant confirming your ticket was received.",
});
 
console.log(call.callId, call.state);

Outbound voice runs behind a server-side TCPA consent gate. It is a one-time attestation your org completes in the console under Settings → Outbound Calling & SMS; until it is done, every outbound call is refused before it reaches the dialer. There is no per-call consent flag. For SMS the flow is anima.messages.sendSms — same agent boundary, different channel. That consistency is useful when you later add fallback logic.

5) Expand capabilities without changing your trust model#

After the quickstart, most teams add at least one of these:

  • Vault-backed secrets for agent credentials, stored in a dedicated encrypted vault.
  • A voice consent gate — a TCPA consent_source assertion enforced server-side on every outbound call.
  • Agent-to-agent messaging — a did:web identifier, a public agent card, and signed envelopes other agents can verify without holding any of your keys.

The value is that you do not need to invent a separate identity model for each capability. The same core identity remains the source of truth for attribution, policy, and audit trails.

Complete quickstart script#

This script puts the full happy path together:

import { Anima } from "@anima-labs/sdk";
 
async function main() {
  const anima = new Anima({ apiKey: process.env.ANIMA_API_KEY! });
 
  const agent = await anima.agents.create({
    orgId: process.env.ANIMA_ORG_ID!,
    name: "Onboarding Agent",
    slug: "onboarding-agent",
  });
 
  await anima.messages.sendEmail({
    agentId: agent.id,
    to: ["ops@example.com"],
    subject: "Agent onboarding complete",
    body: "Agent and channels are live.",
  });
 
  await anima.calls.create({
    agentId: agent.id,
    to: "+15557654321",
    greeting: "Your onboarding workflow completed successfully.",
  });
 
  console.log("Done. Agent:", agent.id);
}
 
main().catch((error) => {
  console.error(error);
  process.exit(1);
});

From here, you can move directly into production hardening: policy scoping, webhook verification, channel-specific retries, and observability dashboards. The important part is already done: your agent now has a first-class identity and can operate across communication surfaces cleanly.

Stay Updated

Get the latest on AI agent identity, delivered weekly.