Documentation

Quickstart

Test with an existing agent in manual mode, or enforce permissions from your own app with the SDK.

Path A: test with an existing agent

  1. Create account. Sign up at /signup and open the developer dashboard.
  2. Add existing agent. Open /dashboard/onboarding and choose I use an existing agent.
  3. Create first permission. Choose a template. For access_data on gmail.com: set allowed actions to read labels, summarize messages and blocked actions to send email, delete email. For purchase on coachella.com: set max amount to 800. Agent descriptions are informational; permissions are the source of truth.
  4. Open passport link. The passport page shows the agent's allowed scopes, copyable agent memory block, machine-readable JSON, and a manual preview form.
  5. Copy instructions. Paste the generated instructions into Ollie, ChatGPT, Claude, or another assistant. The instructions direct the agent to open the passport link, read the Allowed scopes section, and ask you to verify before acting.
  6. Agents that cannot fetch passport links. Passport links use a #token=… URL fragment. Agents like Gemini memory, ChatGPT system prompts, or Claude project instructions do not execute JavaScript and cannot retrieve the scoped data. For these agents, the passport page provides two copyable blocks: the Agent memory block (paste into the agent's memory or system prompt — best-effort, some assistants compress or ignore saved memory) and the Per-task permission prompt (paste directly into the active chat where the agent is about to act — more reliable because it is in the active context window, not stored state).
  7. Understand the limitation. Manual mode does not control the provider directly, and it relies on agent cooperation. Automatic enforcement requires API integration.

Path B: enforce in your app (fail closed)

  1. Create native agent. Choose I'm building my own agent and store the one-time API key.
  2. Create permission. Choose a scope template or define a custom action with allowed actions, blocked actions, and constraints.
  3. Install SDK. Add the published Node SDK to your app.
  4. Call verify before action. Use enforceAction to fail closed — denied actions throw before reaching the code that would execute the action.
terminal
npm install @behalfid/sdk
enforce.ts
import { BehalfID } from "@behalfid/sdk";

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

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

// browse_web is allowed — continues.
await enforceAction({ action: "browse_web", vendor: "web" });

// purchase is denied — throws. Next line never runs.
await enforceAction({ action: "purchase", vendor: "coachella.com", amount: 742 });
console.log("Booking ticket..."); // ← never reached
denied response
{
  "requestId": "req_xxx",
  "allowed": false,
  "reason": "No active permission exists for this action.",
  "risk": "high"
}

Scope templates

The dashboard and SDK ship with scope templates for common categories. Each template prefills the action, resource, allowed actions, and blocked actions — edit before saving.

scope examples
// Data access
{ action: "access_data", vendor: "gmail.com",
  allowedActions: ["read labels", "summarize messages"],
  blockedActions: ["send email", "delete messages"] }

// Browse web
{ action: "browse_web", vendor: "web",
  allowedActions: ["search web", "read public pages"],
  blockedActions: ["submit forms", "make purchases"] }

// Purchase with constraints
{ action: "purchase", vendor: "coachella.com",
  constraints: { maxAmount: 800, allowedVendors: ["coachella.com"] } }

// Schedule
{ action: "schedule", vendor: "calendar.google.com",
  allowedActions: ["create events", "send invites"],
  blockedActions: ["delete events", "create recurring events"] }