@certisigma/sdk
v1.9.0
Published
Official JavaScript/TypeScript SDK for the CertiSigma attestation & verification API
Downloads
1,212
Maintainers
Readme
CertiSigma JavaScript SDK
Official JavaScript/TypeScript client for the CertiSigma cryptographic attestation API.
Zero dependencies. Works in Node.js 18+ and modern browsers (native fetch).
Installation
npm install @certisigma/sdkOr from source:
cd sdk/js
npm linkQuick Start
(async function main() {
const { CertiSigmaClient, hashFile, hashBytes } = require('@certisigma/sdk');
const fs = require('fs');
const client = new CertiSigmaClient({ apiKey: process.env.CERTISIGMA_API_KEY });
// 1. Compute the SHA-256 hash of your file
const fileHash = await hashFile(fs.readFileSync('contract.pdf'));
// 2. Attest — creates a timestamped, signed proof of existence
const result = await client.attest(fileHash, { source: 'my-app' });
console.log(`Attestation: ${result.id} at ${result.timestamp}`);
// 3. Verify — confirm the hash was attested
const check = await client.verify(fileHash);
console.log(`Exists: ${check.exists}, Level: ${check.level}`);
// Or hash raw bytes
const dataHash = await hashBytes(new TextEncoder().encode('any raw content'));
const result2 = await client.attest(dataHash);
})();Public Verification (No API Key)
Verification endpoints are public. You can verify attestations without any API key:
(async function main() {
const { CertiSigmaClient, hashFile } = require('@certisigma/sdk');
const fs = require('fs');
// No apiKey needed — works out of the box
const client = new CertiSigmaClient();
const fileHash = await hashFile(fs.readFileSync('contract.pdf'));
const check = await client.verify(fileHash);
console.log(`Exists: ${check.exists}, Level: ${check.level}`);
// Batch verify also works without a key
const results = await client.batchVerify([fileHash]);
console.log(`Found: ${results.found}/${results.count}`);
})();TypeScript
Full type definitions included (src/index.d.ts):
import { CertiSigmaClient, CertiSigmaError } from '@certisigma/sdk';
const client = new CertiSigmaClient({ apiKey: process.env.CERTISIGMA_KEY! });
const result = await client.attest(hash); // result is typedBatch Operations
// Attest up to 100 hashes — returns full claim metadata per item
const batch = await client.batchAttest(
['aabb...', 'ccdd...'],
{ source: 'invoice-processor' }
);
console.log(`Created: ${batch.created}, Existing: ${batch.existing}`);
batch.attestations.forEach(a =>
console.log(` ${a.id} claim=${a.claim_id} src=${a.source}`)
);
// Verify batch (public, no key needed)
const results = await client.batchVerify(['aabb...', 'ccdd...']);
console.log(`Found: ${results.found}/${results.count}`);
// Detailed mode — certification level + claim metadata (requires apiKey)
const detailed = await client.batchVerify(['aabb...'], { detailed: true });
detailed.results.filter(r => r.exists).forEach(r =>
console.log(` ${r.id} level=${r.level} src=${r.source}`)
);Attestation Status
Check the current trust tier of an attestation (public, no API key needed):
const status = await client.status('att_1234');
console.log(`Level: ${status.level}`); // "T0", "T1", or "T2"
console.log(`Signature: ${status.signature_available}`);
console.log(`Merkle: ${status.merkle_proof_available}`);
console.log(`OTS: ${status.ots_available}`);| Method | Input | Auth | Best for |
|--------|-------|------|----------|
| verify(hash) | SHA-256 hash | Optional | Compliance checks, "does this hash exist?" |
| status(attId) | Attestation ID | No | Dashboards, progress tracking, polling |
| getEvidence(attId) | Attestation ID | No | Independent verification, long-term archival |
Metadata Management
// Inside an async function
await client.updateMetadata('att_1234', {
source: 'pipeline-v2',
extraData: { project: 'alpha', version: '2.0' },
});
// Soft-delete claim
await client.deleteMetadata('att_1234');
// Get evidence
const evidence = await client.getEvidence('att_1234');Hashing Utilities
Standalone SHA-256 hash functions -- compute hashes without attestation:
(async function main() {
const { hashFile, hashBytes } = require('@certisigma/sdk');
// or: const { hashFile, hashBytes } = require('@certisigma/sdk/hash');
// Hash a File, Blob, ArrayBuffer, or Uint8Array
const fileHash = await hashFile(fileInput.files[0]);
console.log(`SHA-256: ${fileHash}`);
// Hash raw bytes
const dataHash = await hashBytes(new TextEncoder().encode('raw content'));
// Verify a file against a known hash
const currentHash = await hashFile(fileInput.files[0]);
console.assert(currentHash === fileHash);
})();Or hash + attest in one step (inside an async function):
const file = document.getElementById('fileInput').files[0];
const result = await client.attestFile(file, { source: 'upload-form' });Evidence & OTS Verification
(async function main() {
const { CertiSigmaClient, getBlockchainUrl, saveOtsProof } = require('@certisigma/sdk');
const client = new CertiSigmaClient({ apiKey: process.env.CERTISIGMA_API_KEY });
// Get full cryptographic evidence (T0 + T1 + T2)
const evidence = await client.getEvidence('att_1234');
if (evidence.level === 'T2') {
// Bitcoin block explorer link
console.log(getBlockchainUrl(evidence)); // mempool.space/block/...
console.log(getBlockchainUrl(evidence, 'tx')); // mempool.space/tx/...
// Save the raw .ots proof for independent verification
saveOtsProof(evidence, 'contract.pdf.ots');
// Then verify with: ots verify contract.pdf.ots
}
})();Client-Side Encryption (Zero Knowledge)
(async function main() {
const { generateKey, encryptMetadata, decryptMetadata } = require('@certisigma/sdk/crypto');
// Generate a key (store securely — server never sees it)
const key = await generateKey();
// Encrypt before sending
const encrypted = await encryptMetadata({ secret: 'classified' }, key);
const result = await client.attest(hash, { extraData: encrypted, clientEncrypted: true });
// Decrypt after retrieving (extraData comes from the attest response, not verify)
const plaintext = await decryptMetadata(result.extra_data, key);
})();Error Handling
const { AuthenticationError, RateLimitError, QuotaExceededError } = require('@certisigma/sdk');
// Inside an async function
try {
await client.attest(hash);
} catch (err) {
if (err instanceof AuthenticationError) {
console.error('Invalid API key');
} else if (err instanceof RateLimitError) {
console.error(`Rate limited, retry after ${err.retryAfter}s`);
} else if (err instanceof QuotaExceededError) {
console.error('Monthly quota reached');
}
}Configuration
| Parameter | Default | Description |
|-----------|---------|-------------|
| apiKey | undefined | Bearer token (cs_live_...). Optional for verify/health. |
| baseUrl | https://api.certisigma.ch | API endpoint |
| timeout | 30000 | Request timeout in ms |
Proxy: Platform-dependent. In Node.js, set HTTP_PROXY/HTTPS_PROXY or pass a custom fetch with proxy support (e.g. undici).
Custom TLS CA: Set NODE_EXTRA_CA_CERTS=/path/to/ca.pem for corporate environments.
Retry: Not built-in. Implement at caller level — retry only on 429 and 5xx, fail fast on other 4xx.
Share Tokens (Forensic Metadata Sharing)
Create time-limited, auditable tokens for sharing attestation metadata with forensic analysts:
const token = await client.createShareToken([42, 43, 44], {
expiresIn: 86400,
recipientLabel: 'forensic-analyst',
maxUses: 10,
});
console.log(`Share token: ${token.share_token}`); // shown once, save it
const tokens = await client.listShareTokens();
const info = await client.getShareTokenInfo(token.id);
await client.revokeShareToken(token.id);Structured Tagging
Multi-dimensional classification of attestations with server-side querying:
// Upsert tags (max 50 per attestation per key)
await client.putTags('att_42', [
{ key: 'department', value: 'hr' },
{ key: 'classification', value: 'confidential' },
]);
const tags = await client.getTags('att_42');
// Query by tags — AND semantics, max 10 conditions per query
const results = await client.queryTags(
{ and: [{ key: 'department', value: 'hr' }, { key: 'classification', value: 'confidential' }] },
{ limit: 100 },
);
console.log(`Found ${results.count} matching attestations`);
await client.deleteTag('att_42', 'classification');Tag key format: ^[a-z][a-z0-9_-]{0,62}$ (lowercase, no _ prefix — reserved). Client-encrypted tags (valueEnc + valueNonce hex) are supported but excluded from server-side query.
Census — Derived Lists
Create opaque HMAC-SHA256 derived lists for third-party hash verification without revealing your inventory. Requires census scope and org_id.
const { createHmac } = require('node:crypto');
// Create a derived list
const dl = await client.createDerivedList({
hashes: ['a665a459...', 'b4c9a289...'],
label: 'Partner audit Q1',
expiresInHours: 720,
});
console.log(`List key (save now!): ${dl.list_key}`);
// Third party: match files (no API key needed)
const pub = new CertiSigmaClient();
const fileHash = 'a665a459...';
const derived = createHmac('sha256', Buffer.from(dl.list_key, 'hex'))
.update(fileHash).digest('hex');
const result = await pub.matchDerivedList(dl.id, dl.list_key, [derived]);
console.log(`Matched: ${result.matched}/${result.total}`);
// Owner operations
const lists = await client.listDerivedLists();
const detail = await client.getDerivedList(dl.id);
const sig = await client.getDerivedListSignature(dl.id);
const log = await client.getDerivedListAccessLog(dl.id);
await client.revokeDerivedList(dl.id);Read Metadata
Explicit metadata read without re-verifying:
const meta = await client.getMetadata('att_42');
console.log(`Source: ${meta.source}, Extra: ${JSON.stringify(meta.extra_data)}`);Security & Privacy
CertiSigma is a public attestation platform. Cryptographic proofs (hash, signature, Merkle, OTS) are intentionally public and verifiable by any party. Organizational metadata (source, extraData, tags) is never exposed on public endpoints — only the authenticated API key owner can read their own claim data. Tags are scoped per API key with full tenant isolation. Share tokens provide time-limited, auditable, revocable read-only access to specific attestations — all accesses are logged. For sensitive metadata, use client-side encryption (encryptMetadata()); for sensitive tag values, use client-side encrypted tags (valueEnc + valueNonce).
See the Security & Privacy Model in the full documentation for the complete threat model and data boundary.
Test Vectors
Canonical test vectors with real production data are available for independent T0/T1/T2 verification:
Compatibility
- Follows Semantic Versioning 2.0.0.
- SDK v1.x targets API v1 (
/v1/prefix). Breaking API changes get a new prefix with 12-month deprecation window. - See full SDK documentation for error codes, webhook semantics, T0 signature format, and compatibility policy.
Runtime & Packaging
- Node.js 18+ (native
fetch, Web Crypto API) - Subpath exports:
@certisigma/sdk(main),@certisigma/sdk/hash,@certisigma/sdk/crypto - CommonJS (
require) and ESM (import) supported - Edge runtimes: Vercel Edge, Cloudflare Workers, Deno, Bun — no polyfills required
- Memory:
hashFile()loads the entire file into memory. For large files, prefer streaming hashing or Python'sattest_file(path).
Browser Usage
The SDK uses native fetch and Web Crypto API. With a bundler (webpack, vite, esbuild):
import { CertiSigmaClient } from '@certisigma/sdk';
const client = new CertiSigmaClient({ apiKey: 'YOUR_KEY' });Requirements
- Node.js 18+ or any browser with
fetchsupport - No external dependencies
License
MIT — Ten Sigma Sagl, Lugano, Switzerland
