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',
});
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
100 calls/month free. No signup. No credit card.
@nodatachat/sdk v1.0.0 · 14.9 KB · MIT