New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@chaindoc_io/server-sdk

Package Overview
Dependencies
Maintainers
1
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@chaindoc_io/server-sdk

Server-side SDK for Chaindoc API - document management, signatures, and embedded sessions

Source
npmnpm
Version
2.3.0-alpha.0
Version published
Weekly downloads
3
-92.68%
Maintainers
1
Weekly downloads
 
Created
Source

@chaindoc_io/server-sdk

Official server-side SDK for Chaindoc API - documents, signatures, contracts, invoicing, and webhook-safe integrations.

npm version License: MIT TypeScript Node.js

Features

  • Document Management - Create, update, and version documents with blockchain verification
  • Digital Signatures - Request and collect legally-binding electronic signatures
  • Templates, Contracts, and Billing - Generate documents and contracts from published templates, then manage invoice lifecycle and transactions
  • Embedded Signing - Seamless in-app signing experience with frontend SDK integration
  • Blockchain Verification - Immutable document verification on blockchain
  • Webhook Verification - Verify signed webhook deliveries with replay protection
  • Embedded KYC Enforcement - Require Chaindoc-managed KYC inside the signing iframe
  • Zero Dependencies - Uses native Node.js 18+ APIs (fetch, FormData)
  • TypeScript First - Full type definitions included
  • Automatic Retries - Built-in retry logic with exponential backoff

Installation

npm install @chaindoc_io/server-sdk
yarn add @chaindoc_io/server-sdk
pnpm add @chaindoc_io/server-sdk

Quick Start

import { Chaindoc } from "@chaindoc_io/server-sdk";

const chaindoc = new Chaindoc({
  secretKey: "sk_your_secret_key",
});

// Create embedded session for document signing
const session = await chaindoc.embedded.createSession({
  email: "signer@example.com",
  metadata: {
    documentId: "doc_xxx",
    signatureRequestId: "req_xxx",
  },
});

// Use session.sessionId on frontend with @chaindoc_io/embed-sdk
console.log(session.sessionId);

Complete Example: Document Signing Flow

import { Chaindoc } from "@chaindoc_io/server-sdk";
import { readFile } from "fs/promises";

const chaindoc = new Chaindoc({
  secretKey: "sk_your_secret_key",
});

// 1. Upload document
const buffer = await readFile("./contract.pdf");
const file = new Blob([buffer], { type: "application/pdf" });
const { media } = await chaindoc.media.upload([file]);

// 2. Create document with blockchain verification
const doc = await chaindoc.documents.create({
  name: "Service Agreement",
  description: "Contract for services",
  media: media[0],
  hashtags: ["#contract", "#agreement"],
  status: "published", // Verify in blockchain
});

// 3. Create signature request
const request = await chaindoc.signatures.createRequest({
  versionId: doc.document.currentVersion.id,
  recipients: [{ email: "signer@example.com" }],
  deadline: new Date("2027-12-31"),
  embeddedFlow: true,
  isKycRequired: true,
});

// 4. Create embedded session for signer
const session = await chaindoc.embedded.createSession({
  email: "signer@example.com",
  metadata: {
    documentId: doc.documentId,
    signatureRequestId: request.requestId,
    returnUrl: "https://yourapp.com/signing-complete",
  },
});

// 5. Send sessionId to frontend
// Frontend uses: @chaindoc_io/embed-sdk
// sdk.openSignatureFlow({ sessionId: session.sessionId })

Complete Example: Contract Billing Flow

import { Chaindoc } from "@chaindoc_io/server-sdk";

const chaindoc = new Chaindoc({
  secretKey: "sk_your_secret_key",
});

// Contract should already be created, sent, and signed by both parties
const contract = await chaindoc.contracts.get("contract_uuid");
const contractId = contract.contractId;

if (contract.contract.status !== "active") {
  throw new Error("Invoices can be created only for active contracts");
}

const invoice = await chaindoc.invoices.create(contractId, {
  title: "April Retainer",
  amount: "1500.00",
  dueDate: "2026-04-30T00:00:00.000Z",
  sendImmediately: false,
});

const invoiceId = invoice.invoiceId ?? invoice.invoice.id;

await chaindoc.invoices.send(contractId, invoiceId, {
  autoCharge: false,
});

const refreshedInvoice = await chaindoc.invoices.get(contractId, invoiceId);

if (refreshedInvoice.invoice.status === "unpaid") {
  await chaindoc.invoices.charge(contractId, invoiceId);
}

const transactions = await chaindoc.transactions.listByContract(contractId);

console.log(transactions.transactions.map((transaction) => transaction.id));

Complete Example: Template Runtime Flow

import { Chaindoc } from "@chaindoc_io/server-sdk";

const chaindoc = new Chaindoc({
  secretKey: "sk_your_secret_key",
});

const templateId = "template_uuid";

const draftDocument = await chaindoc.templates.createDocument(templateId, {
  documentName: "Generated NDA",
  documentDescription: "Rendered from a published Chaindoc template",
  variables: {
    client_name: "Acme Inc.",
    effective_date: "2026-04-10",
  },
});

const signatureRequest = await chaindoc.templates.sendForSigning(templateId, {
  documentName: "Generated NDA",
  documentDescription: "Ready for signing",
  variables: {
    client_name: "Acme Inc.",
    effective_date: "2026-04-10",
  },
  slotAssignments: [{ signerKey: "party_a", email: "signer@example.com" }],
  deadline: new Date("2026-12-31"),
});

const contract = await chaindoc.templates.createContract(templateId, {
  title: "Generated Master Services Agreement",
  description: "Contract rendered from template",
  variables: {
    company_name: "Acme Inc.",
    effective_date: "2026-04-10",
  },
  contragent: {
    email: "partner@example.com",
    name: "Partner Corp",
  },
  slotAssignments: [
    { signerKey: "party_a", role: "business" },
    { signerKey: "party_b", role: "contragent" },
  ],
  deadline: new Date("2026-12-31"),
});

console.log(draftDocument.documentId);
console.log(signatureRequest.requestId);
console.log(contract.contractId);

Configuration

const chaindoc = new Chaindoc({
  secretKey: "sk_xxx", // Required - Your secret API key
  environment: "production", // Optional: 'production' | 'staging' | 'development'
  timeout: 30000, // Optional: Request timeout in ms (default: 30000)
  retry: {
    // Optional: Retry configuration
    maxRetries: 3,
    initialDelay: 1000,
    maxDelay: 10000,
  },
});

Environments

EnvironmentAPI URLUse Case
productionhttps://api.chaindoc.io (default)Live production traffic
staginghttps://api-demo.chaindoc.ioPre-release testing
developmenthttps://api-demo.chaindoc.ioDevelopment & debugging

Email handling

The SDK trims and lowercases every email value before sending it to the API. This applies to top-level fields (email, signerEmail) and to nested email fields inside recipients, fields, slotAssignments, accessEmails, and contragent. Your input objects are not mutated — the SDK copies them shallowly before normalizing. This matches the backend's canonical email format and prevents silent auto-link misses for users who registered with a different case.

API Overview

Documents

// Create document
await chaindoc.documents.create({
  name: string;
  description: string;
  media: Media;
  hashtags: string[];
  status: 'draft' | 'published';
  accessType?: 'private' | 'public' | 'restricted';
});

// Update document (creates new version)
await chaindoc.documents.update(documentId, params);

// Update access rights
await chaindoc.documents.updateRights(documentId, {
  accessType: 'restricted',
  accessEmails: [{ email: 'user@example.com', level: 'read' }],
});

// Verify document in blockchain
await chaindoc.documents.verify({ versionHash: '0x...' });

// Get verification status
await chaindoc.documents.getVerificationStatus(versionId);

Signatures

// Create signature request
await chaindoc.signatures.createRequest({
  versionId: string;
  recipients: [{ email: string }];
  deadline: Date;
  embeddedFlow?: boolean;
  isKycRequired?: boolean;
});

// Get request status
await chaindoc.signatures.getRequestStatus(requestId);

// Get all requests
await chaindoc.signatures.getMyRequests({ pageNumber: 1, pageSize: 10 });

// Sign document
await chaindoc.signatures.sign({ requestId, signatureId });

Embedded Sessions

// Create session for frontend signing (sends OTP to email)
const session = await chaindoc.embedded.createSession({
  email: 'signer@example.com',
  metadata: {
    documentId: string;
    signatureRequestId?: string;
    returnUrl?: string;
  },
});
// Returns sessionId for @chaindoc_io/embed-sdk

Contracts

const created = await chaindoc.contracts.create({
  documentId: "doc_uuid",
  title: "Master Services Agreement",
  contragent: { email: "partner@example.com", name: "Partner LLC" },
  paymentMethodRequired: true,
  preferredPaymentMethodType: "card",
});

await chaindoc.contracts.list({ page: 1, limit: 10, status: "active" });
await chaindoc.contracts.get(created.contractId);
await chaindoc.contracts.getStatus(created.contractId);
await chaindoc.contracts.getActivities(created.contractId);
await chaindoc.contracts.send(created.contractId, {
  messageToSigners: "Please review and sign this contract",
  deadline: new Date("2026-12-31"),
  isKycRequired: true,
});
await chaindoc.contracts.cancel(created.contractId);
await chaindoc.contracts.terminate(created.contractId, { reason: "Mutual offboarding" });

Templates

await chaindoc.templates.createDocument(templateId, {
  documentName: "Generated NDA",
  variables: {
    client_name: "Acme Inc.",
  },
});

await chaindoc.templates.sendForSigning(templateId, {
  documentName: "Generated NDA",
  variables: {
    client_name: "Acme Inc.",
  },
  slotAssignments: [{ signerKey: "party_a", email: "signer@example.com" }],
  deadline: new Date("2026-12-31"),
});

await chaindoc.templates.createContract(templateId, {
  title: "Generated MSA",
  variables: {
    company_name: "Acme Inc.",
  },
  contragent: {
    email: "partner@example.com",
  },
  slotAssignments: [
    { signerKey: "party_a", role: "business" },
    { signerKey: "party_b", role: "contragent" },
  ],
  deadline: new Date("2026-12-31"),
});

Invoices

await chaindoc.invoices.create(contractId, {
  title: "April Retainer",
  amount: "1500.00",
  dueDate: "2026-04-30T00:00:00.000Z",
  autoCharge: false,
  sendImmediately: false,
});

await chaindoc.invoices.list(contractId, { status: "unpaid", page: 1, limit: 20 });
await chaindoc.invoices.get(contractId, invoiceId);
await chaindoc.invoices.send(contractId, invoiceId, { autoCharge: true });
await chaindoc.invoices.charge(contractId, invoiceId);
await chaindoc.invoices.markPaid(contractId, invoiceId, { note: "Wire received" });

Transactions

await chaindoc.transactions.listByContract(contractId);
await chaindoc.transactions.get(transactionId);

Media

// Upload files (PDF, DOC, images, videos)
const { media } = await chaindoc.media.upload([file1, file2]);

Utility

// Get API key info
await chaindoc.getApiKeyInfo();

// Health check
await chaindoc.healthCheck();

Webhooks

const verification = Chaindoc.webhooks.verify(
  rawBody,
  req.headers["x-chaindoc-signature"] as string,
  req.headers["x-chaindoc-timestamp"] as string,
  process.env.CHAINDOC_WEBHOOK_SECRET!
);

if (!verification.valid) {
  throw new Error("Invalid webhook signature");
}

switch (verification.envelope?.type) {
  case "contract.signed":
  case "invoice.created":
  case "invoice.sent":
  case "invoice.paid":
  case "transaction.created":
  case "transaction.updated":
    console.log(verification.envelope.data);
    break;
}

Error Handling

import { Chaindoc, ChaindocError } from '@chaindoc_io/server-sdk';

try {
  await chaindoc.documents.create({ ... });
} catch (error) {
  if (error instanceof ChaindocError) {
    console.error('API Error:', error.message);
    console.error('Status:', error.statusCode);
    console.error('Response:', error.response);
  }
}

Documentation

Requirements

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Security

For security vulnerabilities, please see our Security Policy.

License

MIT License - see LICENSE file for details.

Support

Made with ❤️ by the Chaindoc team

Keywords

chaindoc

FAQs

Package last updated on 15 Jul 2026

Related posts