TypeScript SDK
npmFull 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.
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.
// 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
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
Approval flow
Gate dangerous actions behind human approval with rich context and action buttons.
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(); Card with diff
Present code reviews with diffs, stats, and action buttons in a single composable card.
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" },
],
} },
],
}],
}); Data report with chart
Deliver structured reports with metrics, tables, and charts that humans can review at a glance.
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.
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
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}`);
}
}