Documentation

REST API, SDK, protocol reference, and team management for PARAMANT Ghost Pipe v2.

Quick start

Send your first encrypted blob in under 5 minutes.

python
# pip install paramant-sdk
from paramant_sdk import GhostPipe

gp   = GhostPipe("pgp_xxx", "mri-scanner-001")
hash = gp.send(patient_record)  # ML-KEM-768 encrypted
data = gp.receive(hash)         # burn-on-read — then gone

# delivered. destroyed. zero trace.
# Python SDK
pip install paramant-sdk

from paramant_sdk import GhostPipe

gp   = GhostPipe("pgp_your_key", "device-001")
hash = gp.send(open("document.pdf", "rb").read())
data = gp.receive(hash)   # burn-on-read — then gone forever
# Direct HTTP — no SDK needed
curl -X POST https://health.paramant.app/v2/inbound \
  -H "X-Api-Key: pgp_your_key" \
  -H "Content-Type: application/json" \
  -d '{"hash":"sha256_of_payload","payload":"base64_blob","ttl_ms":300000}'

Authentication

All endpoints require an API key as a header or query parameter.

X-Api-Key: pgp_your_key_here
# or via query param
GET /v2/check-key?k=pgp_your_key_here

Keys are plan-based: devproenterprise

SDK & scripts

The Python SDK and CLI scripts handle encryption, chunking, retries, and DID auth automatically. Download them below — your API key is required to use the relay.

↓ paramant-sender.py ↓ paramant-receiver.py ↓ paramant_sdk.py
gp = GhostPipe(
    api_key="pgp_xxx",
    device="device-001",
    sector="health",          # routing hint — picks health.paramant.app
    use_edge=False            # True = via Fly.io edge (geo-routed)
)

All sectors expose the same API — sector selects the routing domain only.

hash = gp.send(data, ttl_ms=86400000, webhook="https://you.com/cb")
data = gp.receive(hash)

All endpoints

MethodEndpointDescriptionAuth
GET/healthNode status, version, uptime, slots
POST/v2/inboundUpload encrypted blobKey
GET/v2/outbound/:hashDownload + burn — one retrieval onlyKey
GET/v2/status/:hashCheck availability without consumingKey
POST/v2/ackConfirm delivery, log latencyKey
GET/v2/monitorLive delivery stats, ACK rateKey
POST/v2/ws-ticketGet 30s one-time WebSocket ticket (avoids key in URL)Key
GET/v2/streamWebSocket — blob_ready push eventsTicket or Key
POST/v2/webhookRegister delivery webhook URLKey
POST/v2/pubkeyRegister ML-KEM + ECDH keypairKey
GET/v2/check-keyVerify key validity and plan
POST/v2/did/registerRegister W3C Decentralized IdentityKey
GET/v2/did/:didResolve DID document
GET/v2/ct/logCertificate Transparency log
GET/v2/auditMerkle audit chain — JSON + CSV exportKey
GET/v2/key-sectorResolve sector for this keyKey
GET/v2/team/devicesList team devicesKey
POST/v2/team/add-deviceAdd device to team (Pro+)Key
GET/metricsPrometheus scrape endpointAdmin

POST /v2/inbound

Upload an encrypted blob. Stored in RAM only. Returns hash and download token.

{
  "hash":    "sha256_of_padded_payload",
  "payload": "base64_encoded_5mb_blob",
  "ttl_ms":  300000
}

200: { "ok": true, "hash": "...", "ttl_ms": 300000, "download_token": "..." }
409: hash already exists
503: relay at capacity

TTL is clamped to plan maximum: dev 1h · pro 24h · enterprise 7 days.

GET /v2/outbound/:hash

One retrieval only. Blob is overwritten with random bytes and removed from RAM after this call.

GET /v2/outbound/abc123...
X-Api-Key: pgp_xxx

200: binary blob (5MB padded)
404: burned or expired
403: wrong API key

GET /v2/monitor

{
  "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

{ "hash": "blob_hash", "callback_url": "https://you.com/hook" }

Payload on delivery:
{ "event": "blob_retrieved", "hash": "...", "ts": "2026-04-02T..." }

GET /v2/stream

Preferred: fetch a 30-second one-time ticket first to avoid putting the API key in the URL.

// Step 1 — get a one-time WebSocket ticket (30s TTL)
const { ticket } = await fetch('https://health.paramant.app/v2/ws-ticket', {
  method: 'POST', headers: { 'X-Api-Key': 'pgp_xxx' }
}).then(r => r.json());

// Step 2 — connect with ticket (key never appears in URL)
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: 5242880 }
}

Crypto stack

AlgorithmRoleStandard
ML-KEM-768Post-quantum key encapsulationNIST FIPS 203
ECDH P-256Classical key exchange (hybrid)NIST SP 800-56A
AES-256-GCMSymmetric encryptionNIST FIPS 197
HKDF-SHA256Key derivationRFC 5869
SHA3-256Merkle CT log · DID hashes · PSS commitmentsNIST FIPS 202
ML-DSA-65Post-quantum signatures (optional)NIST FIPS 204

Burn-on-read

After GET /v2/outbound/:hash the relay overwrites the blob buffer with random bytes and removes it from memory. Encrypted payload data is never written to disk. No backup, no recovery. (The CT log persists cryptographic hashes to disk, but never payload content.)

5MB fixed padding

All blobs are padded to exactly 5MB with cryptographically random bytes before upload. An observer on the network cannot determine the size or type of the transferred file.

W3C Decentralized Identity

POST /v2/did/register
{ "device_id": "mri-001", "ecdh_pub": "base64...", "dsa_pub": "base64..." }

{ "did": "did:paramant:abc123...", "ct_index": 42 }

# Authenticate subsequent requests:
X-DID: did:paramant:abc123...
X-DID-Signature: base64_request_signed_with_dsa_key

Certificate Transparency log

Every public key registration is appended to a public Merkle tree at GET /v2/ct/log. Anyone can verify a device registration without seeing transferred data.

Team management

# Create team
python3 paramant-admin.py team-create --label my-org --stripe-sub sub_xxx --sector health

# Add device — auto-bills +€12/mo
python3 paramant-admin.py team-add --team team_abc123 --label laptop-jan --sector health

# List teams
python3 paramant-admin.py team-list

Retention policy

PlanDefault TTLMaximum TTL
dev5 min1 hour
pro5 min24 hours
enterprise5 min7 days

Relay routing domains

All sector nodes run identical Ghost Pipe relay software. Separate subdomains exist for traffic routing, isolation, and sector-specific compliance documentation — not for different relay configurations.

DomainURLPrimary use caseCompliance reference
healthhealth.paramant.appDICOM, patient records, vitalsNEN 7510, GDPR
legallegal.paramant.appContracts, notary, evidenceAVG, eIDAS
financefinance.paramant.appCompliance data, signing keysNo CLOUD Act, NIS2/DORA
iotiot.paramant.appSCADA, PLCs, sensor streamsIEC 62443

The sector parameter in the SDK is a routing hint — it selects which subdomain to connect to. The crypto stack, API surface, and burn-on-read behaviour are identical across all domains.