npm install @nodatachat/sdk

Machine-to-Machine SDK

Five lines of code. Zero dependencies. Blind encryption for any system.

Your server should never see what it doesn't need to know.

INSTALL
npmbash
npm install @nodatachat/sdk
Zero dependencies. Works in Node.js, Bun, Deno, Cloudflare Workers — anything with fetch.
5 lines — and your server is blind

Encrypt a field, store it, decrypt it. Our server stores nothing.

TypeScriptts
import { NoData } from '@nodatachat/sdk';

const nd = new NoData({ apiKey: 'sk_live_...' });

// Encrypt — server-blind
const { ciphertext } = await nd.encrypt({
  field: 'credit_card',
  value: '4111111111111111',
});
// Store `ciphertext` in YOUR database. NoData stores nothing.

// Decrypt — audited
const { value } = await nd.decrypt({
  field: 'credit_card',
  ciphertext,
  requester: 'billing-service',
});
Encryption
AES-256-GCM
Server storage
Zero
Audit
Metadata only
BATCH100 fields. One call.
const result = await nd.batchNative([
  { op: 'encrypt', field: 'phone',  value: '0501234567' },
  { op: 'encrypt', field: 'email',  value: 'david@company.com' },
  { op: 'encrypt', field: 'id',     value: '123456789' },
  { op: 'decrypt', field: 'ssn',    ciphertext: 'aes256gcm:v1:...' },
]);
// result.ok === 4, result.failed === 0
or — encrypt an entire objectts
const encrypted = await nd.encryptObject(
  { name: 'David', phone: '050...', email: 'd@x.com', age: 30 },
  ['phone', 'email']
);
// { name: 'David', phone: 'aes256gcm:v1:...', email: 'aes256gcm:v1:...', age: 30 }

Modules

🔐encrypt / decrypt

Field-level blind relay. Server encrypts, returns ciphertext. Stores nothing.

nd.encrypt()nd.decrypt()nd.batchNative()nd.encryptObject()
🔗channel

Secure tunnels between systems. E2E encrypted. Verification codes. Burn-after-read.

nd.channel.create()nd.channel.send()nd.channel.receive()nd.channel.proof()
🪝webhook

Receive webhooks encrypted at rest. PBKDF2 + AES-256-GCM. You hold the key.

nd.webhook.create()nd.webhook.events()nd.webhook.list()
🔥deliver

Burn-after-read delivery. One link. One view. Gone.

nd.deliver.send()nd.deliver.burn()nd.deliver.read()
📋evidence

SOC-ready audit trail. Metadata only — never content. Proof certificates.

nd.evidence.query()nd.evidence.certificate()nd.evidence.verify()
🏦vault

Zero-knowledge storage. You encrypt client-side. Server stores blindly.

nd.vault.create()nd.vault.read()nd.vault.delete()
M2MSecure Channel — system to system

Two systems need to exchange sensitive data. Neither trusts the other's infra. NoData sits in the middle — blind.

// System A — creates a channel
const ch = await nd.channel.create({
  ttl: '1h',
  requireVerification: true,
});

// System B — sends credit card data
await nd.channel.send({
  token: ch.channel_token,
  data: { card: '4111111111111111', cvv: '123', exp: '12/28' },
  burnAfterRead: true,
});

// System A — receives
const result = await nd.channel.receive({
  token: ch.channel_token,
  verificationCode: '482901',
});
const card = JSON.parse(result.data);
System A ──── channel.create() ────→ NoData ←──── channel.send() ──── System B
Server relays encrypted bytes. Sees nothing. Stores nothing.
PLUGINOne line — Express / Fastify

Large system? No rewrite needed. One line of middleware — every response with sensitive fields auto-encrypted.

Expressts
import express from 'express';
import { nodataExpress } from '@nodatachat/sdk/express';

const app = express();

app.use('/api/customers', nodataExpress({
  apiKey: 'sk_live_...',
  encryptFields: ['phone', 'email', 'id_number'],
}));

// Every response with phone/email/id_number → auto-encrypted
// No code changes in your routes
Fastifyts
import Fastify from 'fastify';
import { nodataFastify } from '@nodatachat/sdk/fastify';

const app = Fastify();

app.register(nodataFastify, {
  apiKey: 'sk_live_...',
  encryptFields: ['phone', 'email', 'id_number'],
});
AUTHService Accounts — scoped keys

Master key (sk_live_) creates restricted service accounts — scopes, rate limit, IP whitelist, expiry.

// Master key creates a scoped service account
const res = await fetch('/api/v1/service-account', {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_live_MASTER_KEY' },
  body: JSON.stringify({
    name: 'payment-service',
    scopes: ['encrypt', 'decrypt'],
    rate_limit_per_minute: 500,
    daily_quota: 100000,
    expires_in_days: 90,
    allowed_ips: ['10.0.0.0/8'],
  }),
});
// → { key: "svc_live_abc123..." } — shown ONCE
sk_live_
Master key
All scopes, creates child keys
svc_live_
Service account
Restricted scopes, IP whitelist, expiry
Any language that speaks HTTP
import { NoData } from '@nodatachat/sdk';

const nd = new NoData({ apiKey: process.env.NODATA_API_KEY! });

const { ciphertext } = await nd.encrypt({
  field: 'ssn',
  value: '123-45-6789',
});

// Store in your DB. NoData stores nothing.
await db.query('UPDATE users SET ssn = $1 WHERE id = $2', [ciphertext, userId]);
Architecture
┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ Your App │ ──────→ │ NoData API │ ──────→ │ Your DB │ │ │ │ │ │ │ │ plaintext │ │ ciphertext │ │ ciphertext │ │ lives here │ │ passes thru │ │ stored here│ │ │ │ stores: 0 │ │ │ └─────────────┘ └──────────────┘ └─────────────┘

NoData is a relay, not a vault. Data flows through, gets encrypted, and leaves. The server is blind by design — not by policy.

Why
🚫Zero plaintext on our servers — ever
🔑Zero key storage — you hold everything
📦Zero data retention — we're a relay, not a warehouse
📋Full audit trail — every operation logged (metadata only)
SOC 2 ready — evidence endpoint = auditor-friendly
0️⃣Zero dependencies — just fetch
Get API key — freenpm ↗

100 calls/month free. No signup. No credit card.

@nodatachat/sdk v1.0.0 · 14.9 KB · MIT