Start here

SDKs

Public packages: @zerogrant/browser, @zerogrant/node, @zerogrant/react, @zerogrant/webhook-contracts (restricted npm org publish via Changesets / sdk-publish workflow). Locally: make pack-sdks dry-run. Secret keys stay on the server. Publishable keys and intent client_secret are what the browser may hold.

$ npm install @zerogrant/browser @zerogrant/node
install.sh
npm install @zerogrant/browser @zerogrant/node @zerogrant/webhook-contracts
# optional React bindings
npm install @zerogrant/react

Node (secret key)

server.ts
import { ZeroGrant } from "@zerogrant/node";

const zg = new ZeroGrant({
  apiKey: process.env.ZEROGRANT_SECRET_KEY!, // zg_test_...
  baseUrl: "https://api.zerogrant.io",
});

const intent = await zg.clearanceIntents.create({
  customerReference: "demo_user",
  purpose: "sandbox_clearance",
});

// intent.client_secret -> pass to browser Element (shown once)

await zg.policies.list();
await zg.complianceEvidence.download();
await zg.billing.invoices();

Browser (publishable key)

client.ts
import { loadZeroGrant } from "@zerogrant/browser";

const zeroGrant = await loadZeroGrant(
  process.env.NEXT_PUBLIC_ZEROGRANT_PUBLISHABLE_KEY!, // pk_test_...
  { apiBaseUrl: "https://api.zerogrant.io" },
);

const clearance = zeroGrant.elements.create("clearance", {
  clientSecret: intentClientSecret,
  onSucceeded: (result) => console.log(result),
});
clearance.mount("#zerogrant-clearance");

Keys

Create secret and publishable keys in the dashboard (or POST /v1/api-keys). The secret plaintext is returned once at create time; list and evidence endpoints never re-expose it.

Element session routes: GET /v1/element/session, POST /v1/element/session/approve, POST /v1/element/session/decline (Bearer ci_secret_...). Publishable config: GET /v1/element/config.