Documentation
JavaScript SDK
The SDK is published as @behalfid/sdk and uses fetch, so it works in Node 18+ without extra dependencies.
Install
npm install @behalfid/sdk
The package is published on npm as @behalfid/sdk.
Initialize
import { BehalfID } from "@behalfid/sdk";
const behalf = new BehalfID({
apiKey: process.env.BEHALFID_API_KEY!,
baseUrl: "https://behalfid.com"
});Add a connected agent
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
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. Active blocked actions override allows, and non-empty allowed actions narrow the permission to those exact action strings.
Fail-closed enforcement
Gate every external action with verify. On denial, throw or return before calling the executor. This is fail closed: verify first, execute second, and stop when permission is missing, approval is required, constraints are missing, or a check fails.
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 reachedVerify an action
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 the exact action string you want to execute. If the permission has allowedActions, that action must appear in the list; a broad parent action does not bypass the narrowed scope.
Execute through the Action Gateway
executeAction routes execution through BehalfID-controlled infrastructure. The MVP supports only safe public web reads: browse_web on web. Denied actions return executed: false and no fetch happens.
const result = await behalf.executeAction({
agentId,
action: "browse_web",
resource: "web",
input: {
url: "https://example.com"
}
});
if (result.executed) {
console.log(result.result?.title, result.result?.excerpt);
}Logs and key rotation
const logs = await behalf.getLogs(agentId); const rotated = await behalf.rotateKey(agentId);
Webhook signature helper
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"]
});