🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

@chaindoc_io/server-sdk

Package Overview
Dependencies
Maintainers
1
Versions
29
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

latest
Source
npmnpm
Version
2.1.0
Version published
Maintainers
1
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 18 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts