TypeScript SDK

npm

Full E2E encryption (ECDH + HKDF + AES-GCM) -- keys are derived automatically from your API key. All content is encrypted before leaving your process.

npm install @hiloop/sdk

Authentication

All API keys use the format hlp_<64-hex-chars>. Permissions (agent, manage, space, owner) are configured when creating the key via the admin panel. E2E encryption is automatic with all keys.

API key with agent name

Pass agentName to specify which agent identity the key acts as. It's sent as the X-Hiloop header. If the agent doesn't exist yet, it's auto-created.

Multi-agent setup
import { HiloopClient } from "@hiloop/sdk";

// One key, multiple agents
const deployer = new HiloopClient({
  apiKey: "hlp_xxx",
  agentName: "deploy-bot",    // auto-created if new
});

const monitor = new HiloopClient({
  apiKey: "hlp_xxx",
  agentName: "monitor-bot",   // different agent, same key
});

// Or set agent per-call
const client = new HiloopClient({ apiKey: "hlp_xxx" });
await client.send(session.id, {
  components: [{ type: "text", data: { content: "Hello!" } }],
}, { agentName: "support-bot" });

Provisioning API key hlp_prov_*

Provisioning keys create and manage agents programmatically (headless). They cannot be used with HiloopClient directly -- use them to create agent keys via POST /v1/provision/agents, then use the returned agent key.

Provisioning flow
// Step 1: Create agent via provisioning API
const res = await fetch("https://api.hi-loop.com/v1/provision/agents", {
  method: "POST",
  headers: {
    "X-API-Key": "hlp_prov_xxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "my-agent", description: "CI/CD bot" }),
});
const { agent, apiKey } = await res.json();

// Step 2: Use the returned agent key
const client = new HiloopClient({ apiKey });

Auto-creation

Sessions and agents are auto-created when you first use them -- no setup required.

Resource Auto-created? How
Agents Yes Pass agentName with your API key. Created on first API call.
Sessions Yes createConvSession() or send a message with a new session ID.
Channels No Must call createChannel() explicitly.

You can also pre-create agents and sessions via the dashboard UI or the provisioning API.

Quick start

agent.ts
import { HiloopClient } from "@hiloop/sdk";

const client = new HiloopClient({
  apiKey: "hlp_xxx",
  agentName: "my-bot",
});

// Create a session (auto-creates agent if needed)
const session = await client.createConvSession({
  title: "Deploy v2.4.1?",
});

// Send a message with composable components
await client.send(session.id, {
  components: [
    { type: "text", data: { content: "All tests passing." } },
    { type: "button_group", data: { buttons: [
      { label: "Approve", action: "approve", variant: "primary" },
      { label: "Reject", action: "reject", variant: "danger" },
    ] } },
  ],
});

// Wait for the human to respond
const result = await client.awaitResponse(session.id);
console.log("Decision:", result.response);

Examples

Preview

Approval flow

Gate dangerous actions behind human approval with rich context and action buttons.

agent.ts
import { HiloopClient } from "@hiloop/sdk";

const client = new HiloopClient({
  apiKey: "hlp_xxx",
  agentName: "deploy-bot",
});

const session = await client.createConvSession({
  title: "Deploy v2.4.1 to production?",
});

await client.send(session.id, {
  components: [
    { type: "kv", data: { entries: [
      { key: "Service", value: "api-gateway" },
      { key: "Version", value: "2.4.1" },
      { key: "Changes", value: "12 features, 34 fixes" },
    ] } },
    { type: "button_group", data: { buttons: [
      { label: "Approve", action: "approve", variant: "primary" },
      { label: "Reject", action: "reject", variant: "danger" },
    ] } },
  ],
});

const result = await client.awaitResponse(session.id);
if (result.response === "approve") deploy();
Preview

Card with diff

Present code reviews with diffs, stats, and action buttons in a single composable card.

agent.ts
await client.send(session.id, {
  components: [{
    type: "card", children: [
      { type: "header",
        data: { title: "PR #247: auth middleware" } },
      { type: "kv", data: { entries: [
        { key: "Tests", value: "142 passed" },
        { key: "Coverage", value: "94.2%" },
      ] } },
      { type: "diff", data: {
        filePath: "src/auth.ts",
        hunks: [{ header: "@@ -12,3 +12,5 @@",
          lines: [
            { type: "context",
              content: "  const token = getToken();" },
            { type: "add",
              content: "  if (!token) return unauthorized();" },
          ],
        }],
      } },
      { type: "button_group", data: {
        buttons: [
          { label: "Approve", value: "approve" },
          { label: "Changes", value: "changes" },
        ],
      } },
    ],
  }],
});
Preview

Data report with chart

Deliver structured reports with metrics, tables, and charts that humans can review at a glance.

agent.ts
await client.send(session.id, {
  components: [
    { type: "metric_grid", data: { metrics: [
      { label: "Revenue", value: "$4.87M", change: "+14%" },
      { label: "New MRR", value: "$312K", change: "+8%" },
      { label: "Churn", value: "1.2%", change: "-0.3%" },
    ] } },
    { type: "chart", data: {
      type: "bar",
      labels: ["Jan", "Feb", "Mar", "Apr"],
      datasets: [{ label: "Revenue",
        data: [320, 410, 380, 487] }],
    } },
  ],
});

API Reference

All methods handle E2E encryption automatically. Content is encrypted before leaving your process and decrypted on read.

Sessions

Sessions are conversations between an agent and one or more humans.

createConvSession(opts)

Create a new conversation session. Returns the session object with id, status, isPublic.

const session = await client.createConvSession({
  title: "Deploy approval",  // encrypted
  isPublic: false,           // optional, default false
  maxGuests: 5,              // optional guest limit
});
getConvSession(sessionId)

Fetch a single session by ID.

listConvSessions(opts?)

List all sessions for this agent. Filter by status, isPublic, paginate with limit/offset.

closeConvSession(sessionId)

Close a session. No more messages can be sent after closing.

archiveConvSession(sessionId)

Archive a session. Moves it out of the active list.

Messaging

send(sessionId, message, opts?)

Send a message with composable components. This is the primary way to communicate with humans.

await client.send(session.id, {
  components: [
    { type: "text", data: { content: "Deploy ready." } },
    { type: "button_group", data: { buttons: [
      { label: "Approve", action: "approve", variant: "primary" },
    ] } },
  ],
}, {
  agentName: "deploy-bot",     // optional, override agent identity
  priority: "high",            // optional
  referenceId: "tool_call_1",  // optional correlation key
});
sendText(sessionId, text, opts?)

Shorthand for sending a plain text message.

await client.sendText(session.id, "Looking into your request...");
awaitResponse(sessionId, opts?)

Block until a human responds. Returns the response content. Supports timeoutMs and pollIntervalMs.

const result = await client.awaitResponse(session.id, {
  timeoutMs: 300000,     // 5 min timeout (default: 5 min)
  pollIntervalMs: 2000,  // poll every 2s (default: 2s)
});
console.log(result.response);  // "approve"
acknowledge(sessionId)

Acknowledge receipt of a response. Marks the interaction as completed.

cancel(sessionId)

Cancel a pending interaction.

sendConvSessionTyping(sessionId, typing)

Send a typing indicator. Set true when processing, false when done.

editConvSessionMessage(sessionId, msgId, content)

Edit a previously sent message.

deleteConvSessionMessage(sessionId, msgId)

Delete a message from a session.

listConvSessionTimeline(sessionId, opts?)

Fetch the full timeline (messages + interactions) for a session. Paginate with limit/before.

Participants

addConvSessionParticipant(sessionId, userId, role?)

Add a user to a session. Role can be "owner", "admin", "member", "viewer", or "guest".

removeConvSessionParticipant(sessionId, userId)

Remove a user from a session.

updateConvSessionParticipantRole(sessionId, userId, role)

Change a participant's role.

listConvSessionParticipants(sessionId)

List all participants in a session with their names and roles.

Guest access

Let external users join sessions without an account via guest tokens.

createGuestToken(sessionId, opts)

Create a guest access token. Optionally set maxUses and expiresAt.

const token = await client.createGuestToken(session.id, {
  maxUses: 1,
  expiresAt: "2025-12-31T23:59:59Z",
});
console.log(token.publicUrl);  // shareable link
listGuestTokens(sessionId)

List all guest tokens for a session.

revokeGuestToken(sessionId, tokenId)

Revoke a guest token immediately.

Attachments

uploadSessionAttachment(sessionId, data, filename, mimeType)

Upload a file attachment to a session. Content is encrypted.

listSessionAttachments(sessionId)

List all attachments in a session.

downloadSessionAttachment(sessionId, fileId)

Download and decrypt an attachment. Returns an ArrayBuffer.

Channels

Agent-to-agent encrypted messaging channels.

createChannel(opts)

Create a new channel between agents.

const channel = await client.createChannel({
  name: "deploy-alerts",
  participants: ["agent-id-1", "agent-id-2"],
});
sendChannelMessage(channelId, content)

Send an encrypted message to a channel.

listChannelMessages(channelId, opts?)

List messages in a channel. Paginate with limit/before.

getChannel(channelId) / listChannels(opts?) / closeChannel(channelId)

Standard CRUD for channels.

addChannelParticipant / removeChannelParticipant / listChannelParticipants

Manage channel membership.

Webhooks

Webhooks are configured centrally via the admin panel (Admin > Webhooks), not per-agent. Each webhook covers a scope of spaces and agents. Events are automatically delivered to matching webhook endpoints.

decryptWebhookPayload(payload)

Decrypt an incoming webhook payload. Returns the payload with content and components decrypted.

export async function handler(req) {
  const decrypted = await client.decryptWebhookPayload(req.body);
  console.log(decrypted.content);
  console.log(decrypted.components); // ComponentNode[]
}
listWebhookDeliveries(limit?) / retryWebhookDelivery(id) / getWebhookDeliveryStats()

Inspect and retry webhook deliveries for your agent.

Commands (tool calling)

Register commands that humans can invoke from the UI. Your agent receives invocations and completes them.

registerCommands(commands)

Register one or more commands with name, description, and parameter schema.

await client.registerCommands([{
  name: "deploy",
  description: "Deploy a service to production",
  parameters: {
    type: "object",
    properties: {
      service: { type: "string" },
      version: { type: "string" },
    },
    required: ["service", "version"],
  },
}]);
getInvocations(opts?)

Poll for pending command invocations.

completeInvocation(id, result) / failInvocation(id, error)

Report command completion or failure.

Encryption

decryptSessionMessage(encryptedContent)

Decrypt a session message's content string.

getEncryptionInfo()

Get the space's public key ID and public key for manual encryption.

getAgentPublicKey() / putAgentPublicKey(publicKey, fingerprint)

Get or register this agent's X25519 public key.

Utilities

getQuota()

Get current plan limits and usage (sessions, messages, voice minutes).

listSpaceUsers(opts?) / listSpaceTeams()

List users and teams in the space.

getUserAvailability(userId)

Check if a user is available for interactions.

logActivity(entry) / logComm(opts) / pushTelemetry(opts)

Log agent activity, communication events, and push telemetry metrics.

getPublicAgentInfo(slug) / getPublicSession(token) / joinPublicSession(token, name)

Public-facing endpoints for guest access and agent discovery.

Real-time WebSocket

For real-time messaging, use HiloopWsClient. It connects via WebSocket, auto-encrypts outgoing messages, and delivers incoming messages with full encrypted content.

agent.ts
import { HiloopWsClient } from "@hiloop/sdk";

const ws = new HiloopWsClient({
  apiKey: "hlp_xxx",
  agentName: "support-bot",
});

// Receive messages from all sessions (auto-decrypted)
ws.on("session.message.new", (msg) => {
  console.log(`[${msg.sessionId}] ${msg.senderName}: "${msg.content}"`);
});

await ws.connect();

// Send a message to a session
await ws.sendSessionMessage(session.id, "Hey! How can I help?");

No manual subscription needed -- agents automatically receive messages for all their sessions. The WebSocket supports auto-reconnect with exponential backoff.

Error handling

TypeScript
import { HiloopError } from "@hiloop/sdk";

try {
  const session = await client.createConvSession({ title: "Deploy?" });
} catch (err) {
  if (err instanceof HiloopError) {
    console.error(`API error ${err.statusCode}: ${err.message}`);
  }
}

See also