Documentation

JavaScript SDK

The SDK is published as @behalfid/sdk and uses fetch, so it works in Node 18+ without extra dependencies.

Install

terminal
npm install @behalfid/sdk

Initialize

client.ts
import { BehalfID } from "@behalfid/sdk";

const behalf = new BehalfID({
  apiKey: process.env.BEHALFID_API_KEY!,
  baseUrl: "https://behalfid.vercel.app"
});

Add a connected agent

connected-agent.ts
const agent = await behalf.createAgent({
  name: "Ollie",
  agentType: "connected",
  provider: "ollie",
  externalAgentLabel: "Jasper's Ollie assistant",
  description: "Personal assistant used for planning"
});

Create a permission with structured scopes

permission.ts
await behalf.createPermission({
  agentId,
  action: "access_data",
  resource: "gmail.com",
  allowedActions: ["read labels", "summarize messages", "provide pricing metrics"],
  blockedActions: ["send email", "delete messages", "schedule events", "make purchases"],
  requiresApproval: true,
  template: "access_data"
});

Agent descriptions are informational. Permissions are the source of truth. Use allowedActions and blockedActions to make the permission explicit so external agents can read them from the passport page.

Fail-closed enforcement

Use enforceAction to gate every external action. On denial, this throws — the agent never reaches the code that would have executed the action. This is fail closed: on denial, the safe default is to stop.

enforce.ts
async function enforceAction(input) {
  const result = await behalf.verify({ agentId, ...input });
  if (!result.allowed) {
    throw new Error(`Action blocked by BehalfID: ${result.reason}`);
  }
  return result;
}

// Allowed — proceeds.
await enforceAction({ action: "browse_web", vendor: "web" });

// Denied — throws. The next line never runs.
await enforceAction({ action: "purchase", vendor: "coachella.com", amount: 742 });
console.log("Booking ticket..."); // ← never reached

Verify an action

verify.ts
const result = await behalf.verify({
  agentId,
  action: "access_data",
  vendor: "gmail.com",
  metadata: {
    scope: "read labels"
  }
});

In the current API, vendor can represent the resource or service being accessed. Pass amount only for transaction-like actions. Pass metadata.scope to hint which allowed action is being requested.

Logs and key rotation

keys-and-logs.ts
const logs = await behalf.getLogs(agentId);
const rotated = await behalf.rotateKey(agentId);

Webhook signature helper

webhook.ts
import { verifyWebhookSignature } from "@behalfid/sdk";

const valid = await verifyWebhookSignature({
  secret: process.env.BEHALFID_WEBHOOK_SECRET!,
  payload: rawBody,
  timestamp: req.headers["behalfid-timestamp"],
  signature: req.headers["behalfid-signature"]
});