@certynix/sdk
v1.0.0
Published
Official Node.js/TypeScript SDK for Certynix Trust Infrastructure API
Readme
@certynix/sdk
Official Node.js/TypeScript SDK for the Certynix Trust Infrastructure API.
Installation
npm install @certynix/sdkRequires Node.js 18+ (uses native fetch and node:crypto).
Quick Start
import { CertynixClient } from '@certynix/sdk';
const client = new CertynixClient({
apiKey: process.env.CERTYNIX_API_KEY!, // cnx_live_sk_... or cnx_test_sk_...
});
// Register an asset by SHA-256 hash
const asset = await client.assets.register({
hash_sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
filename: 'contract-2024.pdf',
});
console.log(asset.id, asset.status, asset.isFirstRegistrant);
// Public verification (no auth required)
const result = await client.verify.byHash(asset.hash);
console.log(result.match, result.certifiers);Authentication
// Production
const client = new CertynixClient({ apiKey: 'cnx_live_sk_...' });
// Sandbox (auto-detected from key prefix)
const sandbox = new CertynixClient({ apiKey: 'cnx_test_sk_...' });
// With JWT for management endpoints (api-keys, webhooks)
const clientWithJwt = new CertynixClient({
apiKey: 'cnx_live_sk_...',
accessToken: 'eyJ...',
});Assets
// Register by hash
const asset = await client.assets.register({ hash_sha256: '...' });
// Register by URL
const asset = await client.assets.register({ url: 'https://example.com/doc.pdf' });
// Register by file upload
const buf = await fs.readFile('document.pdf');
const asset = await client.assets.register({ file: buf, filename: 'document.pdf' });
// Batch register (async, up to 1,000)
const batch = await client.assets.registerBatch({
assets: [
{ hash_sha256: 'abc123...' },
{ url: 'https://example.com/file.zip' },
],
});
console.log(batch.jobId, batch.status);
// Get by ID
const asset = await client.assets.get('clx1234...');
// List with automatic pagination
for await (const asset of client.assets.list({ status: 'verified', limit: 100 })) {
console.log(asset.id);
}
// Collect all
const all = await client.assets.list().toArray();
// Delete (soft)
await client.assets.delete('clx1234...');Verification (Public)
// By hash (no auth)
const v = await client.verify.byHash('e3b0c44298fc...');
console.log(v.match, v.certifiers);
// By asset ID
const v = await client.verify.byAssetId('clx1234...');
// By hash via POST
const v = await client.verify.byHashPost('e3b0c44298fc...');Webhooks
// Create
const webhook = await client.webhooks.create({
url: 'https://example.com/webhook',
events: ['asset.created', 'asset.verified', 'exposure.alert.created'],
});
console.log(webhook.signingSecret); // Store securely — shown only once
// Validate incoming webhook signature
import express from 'express';
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = WebhooksResource.validateSignature(
req.body, // Buffer — BEFORE any JSON.parse
req.headers['x-certynix-signature'] as string,
process.env.CERTYNIX_WEBHOOK_SECRET!,
);
console.log(event.type, event.payload);
res.sendStatus(200);
} catch (err) {
res.sendStatus(400);
}
});Error Handling
import {
CertynixError,
NotFoundError,
RateLimitError,
ConflictError,
WebhookSignatureError,
} from '@certynix/sdk';
try {
await client.assets.get('nonexistent');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Not found. Request ID:', err.requestId);
}
if (err instanceof RateLimitError) {
console.log('Rate limited. Retry after:', err.retryAfter, 'seconds');
}
if (err instanceof ConflictError) {
console.log('Asset already registered');
}
}Error Hierarchy
CertynixError
├── ConfigurationError (invalid API key format)
├── AuthenticationError (HTTP 401)
├── PermissionError (HTTP 403)
├── NotFoundError (HTTP 404)
├── ConflictError (HTTP 409)
├── ValidationError (HTTP 400)
├── RateLimitError (HTTP 429) + retryAfter
├── ServerError (HTTP 5xx)
├── NetworkError (timeout, DNS, connection refused)
├── WebhookSignatureError (HMAC mismatch)
└── WebhookReplayError (timestamp > 5 minutes)Configuration
const client = new CertynixClient({
apiKey: 'cnx_live_sk_...', // Required
timeout: 10_000, // ms, default: 30000
maxRetries: 5, // default: 3, max: 10
baseUrl: 'http://localhost:3000', // override (useful for testing)
accessToken: 'eyJ...', // JWT for management endpoints
});Retry Policy
Automatic retry with exponential backoff for:
429 Rate Limited— respectsRetry-Afterheader500, 502, 503, 504— server errorsNetworkError— timeouts, connection refused
No retry for 400, 401, 403, 404, 409.
TypeScript
Full strict TypeScript support:
strict: truenoUncheckedIndexedAccess: trueexactOptionalPropertyTypes: true- Zero
anytypes - Dual ESM + CJS build with
.d.tsdeclarations
