One API mints an isolated, content-blind capsule per customer — documents, members, AI grants, audit, revoke, and an embeddable viewer. Connect from your backend in a few calls. Keep your product; replace the access layer.
Every call is a Bearer request from your backend (never the browser). Get a key at /vault-api/register — a working sandbox key ndp_test_… is issued instantly; verify your email to raise it to production.
// Node · Bun · Deno · Cloudflare Workers — zero dependencies
npm install @nodatachat/sdkPrefer raw HTTP? Every SDK method maps 1:1 to a REST endpoint (see the reference below) — the SDK is optional sugar.
import { NoData } from '@nodatachat/sdk';
const nd = new NoData({ apiKey: 'ndp_…' });
// 1 · Mint a capsule (a customer's isolated workspace)
const cap = await nd.capsules.create({ handle: 'case-4471', display_name: 'Yossi Levy' });
// 2 · Seal a document in — a key per recipient, per-section classification
await cap.documents.add({
title: 'Policy',
sections: [
{ label: 'Summary', classification: 'public', text: 'Public summary.' },
{ label: 'Terms', classification: 'confidential', text: 'Confidential terms.' },
],
recipients: [{ email: 'client@acme.com', classifications: ['public'], code: 'blue-harbor' }],
});
// 3 · Grant a member access across the docs
await cap.members.add({ email: 'client@acme.com', classifications: ['public'], code: 'blue-harbor' });
// 4 · Let an AI agent read ONLY what you allow (denied sections never decrypt)
const g = await cap.ai.grant({ agent_name: 'claims-bot', classifications: ['public'] });
const read = await cap.ai.read({ agent_id: g.agent_id });
// 5 · Signed audit ledger — who opened, when, on which device
const ledger = await cap.audit.get();
// 6 · Kill-switch: crypto-shred + block the key. Every live link 410s.
await cap.revoke({ reason: 'offboarded' });The same in one curl to start:
API=https://www.nodatacapsule.com
curl -X POST "$API/api/v1/capsules" \
-H "Authorization: Bearer ndp_…" \
-H "content-type: application/json" \
-d '{"handle":"case-4471"}'
# → 201 { "capsule_id":"…", "status":"active" }Grant a named agent scoped classifications; on read it gets back only those. Denied sections are never decrypted (deny-by-default), zero-knowledge docs are skipped, and every read is logged as an AI access in the audit ledger.
const g = await cap.ai.grant({ agent_name: 'claims-bot', classifications: ['public'] });
const read = await cap.ai.read({ agent_id: g.agent_id });
// read.documents[].sections → 'public' only; 'confidential' is absent
await cap.ai.revoke(g.agent_id);Mint an origin-bound token for one of the capsule's documents and frame the white-label viewer on your own site. The raw bearer never leaves NoData's origin.
const { embed_url } = await cap.embed({
bearer: '<document bearer from documents.add>',
allowed_origin: 'https://portal.myfirm.com',
ttl_seconds: 3600,
});
// <iframe src={embed_url} />Errors return a JSON body with an error code and a helpful message. On 429 the SDK waits and retries automatically using Retry-After.
Shared engines run underneath the capsule (and File · Code · AI · Data Capsule). Reach for them via nd.engines.* only when you need the raw primitive — they're the machinery, not the integration surface.