Documentation.
API reference, SDK guide, self-hosting, and compliance docs for Paramant v0.1.0. The relay is untrusted by design — it never holds a decryption key.
Quick start
Send your first encrypted file in under 5 minutes. Create a free account (TOTP protected, key visible in dashboard).
bash# Sender
python3 paramant-sender.py --key pgp_your_key --device laptop-01 document.pdf
# → HASH: abc123... (share with the receiver)
# Receiver (burn-on-read: one download only)
python3 paramant-receiver.py --key pgp_your_key --hash abc123...
# → document.pdf saved locally. Blob destroyed on relay.Direct HTTP API access requires no SDK:
bashcurl -X POST https://relay.paramant.app/v2/inbound \
-H "X-Api-Key: pgp_your_key" \
-H "Content-Type: application/json" \
-d '{"hash":"sha256_of_payload","payload":"base64_5mb_blob","ttl_ms":3600000}'
curl https://relay.paramant.app/v2/outbound/abc123... \
-H "X-Api-Key: pgp_your_key" -o received.binAuthentication
Two key types exist — never interchangeable:
pgp_— end-user keys for file operationsplk_— relay operator license keys (in.envonly)
X-Api-Key: pgp_your_key_here
# or:
GET /v2/check-key?k=pgp_your_key_hereSDK & scripts
The Python scripts handle ML-KEM-768 encryption, 5 MB padding, chunking, retries, and DID auth.
pythonfrom paramant_sdk import GhostPipe
gp = GhostPipe(
api_key='pgp_xxx',
device='device-001',
sector='health',
)
hash_ = gp.send(open('scan.dcm', 'rb').read(), ttl=3600)
data = gp.receive(hash_)
# Anonymous drop with 12-word mnemonic
mnemonic = gp.drop(b'sensitive data', ttl=3600)
data = gp.pickup(mnemonic)JavaScript/TypeScript SDK:
typescriptimport { GhostPipe } from '@paramant/sdk';
const gp = new GhostPipe({ apiKey: 'pgp_xxx', device: 'device-001', sector: 'health' });
const hash = await gp.send(new TextEncoder().encode('hi'), 3600);
const data = await gp.receive(hash);Use cases
Each sector relay is tuned for its compliance domain.
bash# Healthcare — NEN 7510, DICOM, HL7 FHIR
python3 paramant-sender.py --key pgp_xxx --device mri-001 --sector health scan.dcm
# Legal — eIDAS-grade evidence
paramant-notary deed.pdf --sign --receipt
# Industrial IoT — IEC 62443 quantum-safe data diode
python3 paramant-sender.py --heartbeat 15 --device plc-factory-01 --sector iot
# Finance — NIS2, DORA, ISO 20022
python3 paramant-sender.py --watch /export/iso20022/ --device bank-nl-01 --sector financeAll endpoints
| Method | Endpoint | Description | Auth |
|---|---|---|---|
| GET | /health | Node status, version, uptime, edition | — |
| POST | /v2/inbound | Upload encrypted blob (RAM-only) | Key |
| GET | /v2/outbound/:hash | Download + burn — one retrieval only | Key |
| GET | /v2/status/:hash | Check blob availability without consuming | Key |
| POST | /v2/ack | Confirm delivery, log latency to CT | Key |
| GET | /v2/monitor | Live stats: blobs in flight, ACK rate | Key |
| POST | /v2/ws-ticket | Get 30s one-time WebSocket ticket | Key |
| GET | /v2/stream | WebSocket push — blob_ready events | Ticket |
| POST | /v2/webhook | Register delivery webhook URL | Key |
| POST | /v2/pubkey | Register ML-KEM + ECDH keypair | Key |
| GET | /v2/check-key | Verify key validity and plan | — |
| POST | /v2/did/register | Register W3C Decentralized Identity | Key |
| GET | /v2/did/:did | Resolve DID document | — |
| GET | /v2/ct/sth | Signed Tree Head (public) | — |
| GET | /v2/ct/leaves | CT log entries with proofs | — |
| GET | /v2/relays | Registered relay nodes and status | — |
| GET | /v2/audit | Merkle audit chain — JSON + CSV export | Key |
| GET | /v2/team/devices | List team devices | Key |
| POST | /v2/team/add-device | Add device to team (Pro+) | Key |
| GET | /metrics | Prometheus scrape endpoint | Admin |
POST /v2/inbound
Upload an encrypted, padded blob. Stored in RAM only. Returns a hash for retrieval.
json{ "hash": "sha256_of_padded_payload", "payload": "base64_encoded_5mb_blob", "ttl_ms": 3600000 }200: { "ok": true, "hash": "...", "ttl_ms": ... } · 409: hash already exists · 503: relay at capacity. TTL clamps to plan max. Hash is SHA-256 of the padded payload.
GET /v2/outbound/:hash
After this call the blob buffer is overwritten with random bytes and removed from RAM.
GET /v2/outbound/abc123...
X-Api-Key: pgp_xxx200: binary blob (5 MB padded) · 404: burned/expired/never existed · 403: API key mismatch.
GET /v2/stream
WebSocket endpoint for real-time blob_ready push. Use a one-time ticket.
javascriptconst { ticket } = await fetch('https://health.paramant.app/v2/ws-ticket', {
method: 'POST', headers: { 'X-Api-Key': 'pgp_xxx' }
}).then(r => r.json());
const ws = new WebSocket(`wss://health.paramant.app/v2/stream?ticket=${ticket}`);
ws.onmessage = e => {
const msg = JSON.parse(e.data); // { type: "blob_ready", hash, size, ts }
};GET /v2/monitor
json{
"ok": true, "plan": "pro", "blobs_in_flight": 3,
"stats": { "inbound": 42, "burned": 38, "webhooks_sent": 12 },
"delivery": { "total": 42, "acked": 38, "success_rate": 0.905 }
}POST /v2/webhook
Relay POSTs to your callback on delivery. Body is HMAC-SHA256 signed via X-Paramant-Sig (secret = your API key).
json{ "hash": "blob_hash", "callback_url": "https://you.com/hook" }
// → { "event": "blob_retrieved", "hash": "...", "ts": "..." }GET /health
json{
"ok": true, "version": "0.1.0", "sector": "health",
"edition": "licensed", "uptime_s": 3600
}Self-hosting — Docker Compose
Community Edition is free forever for up to 5 users. One docker compose up starts 6 containers: five sector relays and an admin panel.
bashgit clone https://github.com/mocrofifa-alt/paramant
cd paramant
cp .env.example .env
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .env
docker compose up -d
curl http://localhost:3000/healthContainer ports: relay-main :3000 · health :3001 · finance :3002 · legal :3003 · iot :3004 · admin :4200. All bind 127.0.0.1 — terminate TLS at nginx.
nginx & TLS
bashapt install -y nginx python3-certbot-nginx
certbot certonly --nginx -d your-domain.com \
-d relay.your-domain.com -d health.your-domain.com \
-d finance.your-domain.com -d legal.your-domain.com \
-d iot.your-domain.comFirst user
bashpython3 scripts/paramant-admin.py add --label alice --plan pro --email alice@example.com
python3 scripts/paramant-admin.py sync # pushes to all sector containers
open https://your-domain.com/admin/Community Edition cap: 5 users. The 6th add returns HTTP 402. Add PLK_KEY to .env to unlock unlimited.
Upgrade
bashcd /opt/paramant
git pull --ff-only
docker compose up -d --buildparamant-client — .deb install
bash# One-line install (Ubuntu / Debian / Pi OS)
curl -fsSL https://paramant.app/install-client.sh | bashCLI reference
paramant-send— Encrypt and upload a file or stdinparamant-receive— Download and decrypt by hashparamant-watch— Watch a directory and auto-sendparamant-stream— Listen for incoming blobs via WebSocketparamant-admin— Manage users, keys, relay configparamant-scan— Discover relay nodes on the network
ParamantOS — operator tools
ParamantOS is a hardened Linux distribution for relay operators. Pre-installed tool categories: setup & diagnostics, relay control, sector tools (referral / notary / legal / payslip / firmware / cra), CT log verification, key management, network, security, backup & data.
Crypto stack
| Algorithm | Role | Standard |
|---|---|---|
| ML-KEM-768 | Post-quantum key encapsulation | NIST FIPS 203 |
| ECDH P-256 | Classical key exchange (hybrid) | NIST SP 800-56A |
| AES-256-GCM | Symmetric authenticated encryption | NIST FIPS 197 |
| HKDF-SHA256 | Key derivation from hybrid KEM output | RFC 5869 |
| SHA3-256 | CT log Merkle hashing · DID hashes | NIST FIPS 202 |
| ML-DSA-65 | Relay identity signatures | NIST FIPS 204 |
| Argon2id | Password-protected blob derive | RFC 9106 |
Burn-on-read
After GET /v2/outbound/:hash the relay overwrites the blob buffer with cryptographically random bytes and removes the entry from memory. Two-step burn: zero-in-place, then Map entry deletion. CT log preserves only Merkle hashes — never payload content.
5 MB fixed padding
ParaShare authenticated blobs are padded to exactly 5,242,880 bytes (5 MiB) with cryptographically random bytes. Effective DPI masking: an observer cannot determine size, type, or content. Anonymous /send blobs retain actual encrypted size up to 5 MB.
Certificate Transparency log
Every transfer hash and device registration appended to a public Merkle tree. Root hash changes with every write and is publicly verifiable. Anyone can prove a transfer occurred without learning what was transferred.
bashGET https://relay.paramant.app/v2/ct/leaves?from=0&to=100json{
"tree_size": 56,
"leaves": [
{ "index": 56, "leaf_hash": "ecb779...", "blob_hash": "ce56ff...",
"sector": "health", "inserted_at": "2026-04-14T19:07:57Z" }
]
}W3C Decentralized Identity
Devices can register a W3C DID backed by ML-DSA-65 + ECDH keys.
bashPOST /v2/did/register
{ "device_id": "mri-001", "ecdh_pub": "base64...", "dsa_pub": "base64..." }
# → { "did": "did:paramant:abc123...", "ct_index": 42 }
# Authenticate with DID:
X-DID: did:paramant:abc123...
X-DID-Signature: base64_request_signed_with_dsa_keyTeam management
bashpython3 scripts/paramant-admin.py add --label "scanner-room-3" --plan pro --email admin@hospital.nl
python3 scripts/paramant-admin.py sync
python3 scripts/paramant-admin.py revoke --label "scanner-room-3"Key changes are zero-downtime — the relay hot-reloads users.json on sync. Revoked keys receive WebSocket close code 4401 within seconds.
Retention policy
| Plan | Default TTL | Maximum TTL | Max file |
|---|---|---|---|
| Free (pgp_) | 1 hour | 1 hour | 5 MB (padded) |
| Pro | 1 hour | 24 hours | 5 MB |
| Enterprise | 1 hour | 7 days | 5 MB (tested 50 MB) |
Relay sectors
All sector nodes run identical Ghost Pipe relay software. Sectors are routing domains — they provide traffic isolation and sector-specific compliance documentation.
| Sector | URL | Use | Compliance |
|---|---|---|---|
| health | health.paramant.app | DICOM, patient records, vitals | NEN 7510, GDPR |
| legal | legal.paramant.app | Contracts, notary, evidence | AVG, eIDAS |
| finance | finance.paramant.app | ISO 20022, compliance data | NIS2, DORA |
| iot | iot.paramant.app | SCADA, PLCs, sensor streams | IEC 62443 |
Threat model
The relay is untrusted by design. Security does not depend on trusting the operator.
A compromised relay can: deny or delay service, learn transfer timing/frequency, observe blob sizes (all 5 MB on ParaShare), block specific device hashes.
A compromised relay cannot: read file contents, substitute registered ML-KEM public keys, forge ML-DSA-65 relay signatures, decrypt stored ciphertext.
Security audits
- Apr 2026 · R. Zwarts (verification) · 14 findings · all resolved (commit e6f216d)
- Apr 2026 · R. Zwarts (independent) · 6 findings · all resolved (commit 0db3ef0)
- Apr 2026 · Ryan Williams · Smart Cyber Solutions · 4C/5H/6M/5L · all resolved (commit 0db3ef0)
Findings publicly documented in SECURITY.md. Report vulnerabilities to privacy@paramant.app.
NIS2 / DORA
NIS2 (EU 2022/2555) supported via post-quantum encryption, Merkle CT log audit trail, EU-only Hetzner DE infrastructure, burn-on-read minimisation, zero-downtime key revocation. Full mapping →
NEN 7510 (Healthcare)
health.paramant.app sector designed for NEN 7510 with encrypted-in-transit-and-at-rest (RAM only), CT log access logging, DID device identity, key-based access control, EU GDPR jurisdiction. Control mapping →
IEC 62443 (Industrial / OT)
iot.paramant.app acts as quantum-safe data diode — PLCs/sensors push outbound only without inbound ports. Fixed 5 MB padding defeats traffic analysis. ML-DSA-65 device signatures. Control mapping →
FAQ
No. Encryption happens in the browser or SDK before the file leaves your device. The relay receives ciphertext it cannot decrypt. Even a full root compromise of the relay server yields only encrypted blobs and Merkle hashes.
The blob buffer is immediately overwritten with random bytes and removed from memory. No recovery, no backup, no second download.
Yes. Up to 5 users, no license key required, no time limit. The 6th user returns HTTP 402 — add a PLK_KEY to .env to unlock unlimited users.
pgp_ keys are for end users (file operations). plk_ keys are relay license keys for operators (in .env, not in API calls). Never interchangeable.
All ParaShare transfers — regardless of actual file size — appear as identical 5 MiB blobs on the network. A passive observer cannot distinguish a 1 KB heartbeat from a 4.9 MB DICOM scan.
Yes. The relay runs on arm64 — Pi 3B+, 4, 5. Minimum 512 MB RAM for a single-sector relay. Use install-pi.sh.
Yes — github.com/Apolloccrypt/paramant-relay under BUSL-1.1. Three independent security audits in April 2026 — all findings publicly documented in SECURITY.md.
The relay protocol: WebSocket-based, post-quantum encrypted transfer where data is stored in RAM only, destroyed after one download, padded to a fixed size.