Installation
Get the Chaindoc SDKs into your project. There are two packages: the Server SDK for backend work (documents, signatures, verification) and the Embed SDK for dropping a signing UI into your frontend.
Before you start
What you'll need
A Chaindoc account with API access (Business plan). Create API keys under Settings → API Access in your dashboard.
Server SDK: Node.js 18+ (uses native fetch, Blob, FormData, File).
Embed SDK: any modern browser. Chrome/Edge 90+, Firefox 88+, Safari 14+, Mobile Safari 14+, Chrome for Android 90+.
Both SDKs have zero runtime dependencies: nothing to pre-install, no peer deps.
If you don't have an account yet, start with the quick start guide to get one set up. Learn more in the Node.js LTS releases.
Server SDK
The Server SDK handles everything on the backend: creating documents, sending signature requests, managing teams, and triggering blockchain verification. It's a thin wrapper around the REST API, so if you've read the API docs, the method names will feel familiar.
Install the package
npm install @chaindoc_io/server-sdkSet up environment variables
Create a .env file in your project root. You'll need your secret key here.
# Your Chaindoc secret key (starts with sk_)
CHAINDOC_SECRET_KEY=sk_xxxxxxxxxxxxx
# Optional: override the API endpoint
# (only needed for self-hosted deployments or custom staging URLs)
# CHAINDOC_API_URL=https://api.chaindoc.ioDon't commit your .env file
Add .env to your .gitignore right away. Use separate keys for dev, staging, and production. If a key leaks, rotate it immediately in your Chaindoc dashboard.
Initialize the SDK
import { Chaindoc } from '@chaindoc_io/server-sdk';
// Basic initialization
export const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// Advanced configuration
export const chaindocAdvanced = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
environment: 'production', // 'production' | 'staging' | 'development'
baseUrl: process.env.CHAINDOC_API_URL, // Optional. overrides the environment-derived URL
timeout: 60000, // ms; default 30000
retry: {
maxRetries: 5, // default 3
baseDelayMs: 1000, // starting backoff delay
maxDelayMs: 10000, // ceiling
},
headers: {
'X-Custom-Header': 'value',
},
});The basic config is enough for most projects. The retry settings are worth tuning if you're processing lots of documents in batch, since the API has rate limits.
Verify your connection
// Test API connection
const health = await chaindoc.healthCheck();
if (health.status === 'ok' && health.apiKeyValid) {
console.log('Connected to Chaindoc API at', health.timestamp);
} else {
console.error('Connection failed');
}If this fails, double-check that your secret key starts with sk_ (not pk_. public keys are for the Embed SDK on the frontend, not the Server SDK). Using a public key where a secret key is expected is the most common mistake.
Embed SDK
The Embed SDK lets you show the Chaindoc signing interface inside your web app. Your users sign documents without leaving your site. It works with React, Vue, Angular, or plain JavaScript.
Install the package
npm install @chaindoc_io/embed-sdkThe CDN option is handy for quick prototypes or sites without a build step. For production, use the npm package so you get tree-shaking and proper version control.
Set up environment variables
The Embed SDK takes a public key (pk_) at initialization. It's safe to include in client-side code. the SDK validates the prefix and keeps it local, but runtime authentication for the signing flow is carried by the sessionId your backend creates (see sdks for details), not by the public key.
# .env.local
REACT_APP_CHAINDOC_PUBLIC_KEY=pk_xxxxx
# or for Next.js
NEXT_PUBLIC_CHAINDOC_PUBLIC_KEY=pk_xxxxxInitialize in your app
// hooks/useChaindoc.ts
import { useRef, useEffect } from 'react';
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
export function useChaindoc() {
const sdkRef = useRef<ChaindocEmbed | null>(null);
useEffect(() => {
sdkRef.current = new ChaindocEmbed({
publicKey: process.env.REACT_APP_CHAINDOC_PUBLIC_KEY!,
environment: 'production',
});
return () => {
sdkRef.current?.destroy();
};
}, []);
return sdkRef.current;
}Framework-specific setup
These examples show how to wire up the Embed SDK as a provider or service in each framework. If you're using the Server SDK on the backend, you don't need a provider; just import it where you need it.
Next.js (App Router)
'use client';
import { createContext, useContext, useEffect, useRef } from 'react';
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
const ChaindocContext = createContext<ChaindocEmbed | null>(null);
export function ChaindocProvider({ children }: { children: React.ReactNode }) {
const sdkRef = useRef<ChaindocEmbed | null>(null);
useEffect(() => {
if (!sdkRef.current) {
sdkRef.current = new ChaindocEmbed({
publicKey: process.env.NEXT_PUBLIC_CHAINDOC_PUBLIC_KEY!,
});
}
return () => {
sdkRef.current?.destroy();
};
}, []);
return (
<ChaindocContext.Provider value={sdkRef.current}>
{children}
</ChaindocContext.Provider>
);
}
export const useChaindoc = () => useContext(ChaindocContext);Next.js (Pages Router)
import type { AppProps } from 'next/app';
import { useEffect, useRef } from 'react';
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
export default function App({ Component, pageProps }: AppProps) {
const sdkRef = useRef<ChaindocEmbed | null>(null);
useEffect(() => {
sdkRef.current = new ChaindocEmbed({
publicKey: process.env.NEXT_PUBLIC_CHAINDOC_PUBLIC_KEY!,
});
return () => {
sdkRef.current?.destroy();
};
}, []);
return <Component {...pageProps} />;
}Nuxt 3
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig();
const chaindoc = new ChaindocEmbed({
publicKey: config.public.chaindocPublicKey,
});
return {
provide: {
chaindoc,
},
};
});Angular
import { Injectable, OnDestroy } from '@angular/core';
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class ChaindocService implements OnDestroy {
private sdk: ChaindocEmbed;
constructor() {
this.sdk = new ChaindocEmbed({
publicKey: environment.chaindocPublicKey,
});
}
getSdk(): ChaindocEmbed {
return this.sdk;
}
ngOnDestroy(): void {
this.sdk.destroy();
}
}TypeScript configuration
Both SDKs ship with full TypeScript definitions. You don't need any extra @types packages.
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"types": ["node"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}If you're on an older TypeScript setup (< 5.0), use "moduleResolution": "node" instead of "bundler".
Development vs. production
API keys don't carry an environment flag. the same sk_ or pk_ key works against production, staging, or development. You pick which Chaindoc environment to hit with the environment option on each SDK. Always keep a separate set of keys for dev and prod so a leak or rotation doesn't take down the other.
Development setup
// Server SDK. point at staging, use dev key from .env
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
environment: 'staging',
});
// Embed SDK. staging + debug logs
const embed = new ChaindocEmbed({
publicKey: process.env.NEXT_PUBLIC_CHAINDOC_PUBLIC_KEY!,
environment: 'staging',
debug: true, // prints postMessage traffic to the console
});debug: true on the Embed SDK prints the postMessage traffic between the iframe and the parent. noisy, but invaluable when the flow gets stuck.
Production setup
// Server SDK. production (environment: 'production' is the default, shown here for clarity)
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
environment: 'production',
});
// Embed SDK. production, debug off
const embed = new ChaindocEmbed({
publicKey: process.env.NEXT_PUBLIC_CHAINDOC_PUBLIC_KEY!,
environment: 'production',
});Verify your installation
Run through these checks to make sure everything's wired up correctly:
- 1Check the SDK versionRun
console.log(ChaindocEmbed.version)in your app. If it prints a version number, the package installed correctly. - 2Test the API connectionCall
chaindoc.healthCheck()from your backend. A successful response means your secret key is valid and the API is reachable. - 3Try a file uploadUpload a small test PDF using
chaindoc.media.upload(). This confirms that auth, networking, and file handling all work. - 4Open the signing UIInitialize the Embed SDK and call
openSignatureFlow()with a test session. If the modal appears, you're good to go.
Troubleshooting
"Module not found" error
This usually means the package didn't install properly or there's a cached version conflict. Clear everything and reinstall:
# npm
rm -rf node_modules package-lock.json
npm install
# yarn
rm -rf node_modules yarn.lock
yarn installTypeScript type errors
Make sure you have Node.js types installed and your tsconfig.json uses the right module resolution. Most issues come from mismatched moduleResolution settings.
npm install --save-dev @types/nodeAPI key errors
If you're getting 401 or 403 responses, here's what to check:
- 401 Unauthorized: the key is invalid or has been revoked. Regenerate it in your dashboard.
- 403 Forbidden: your plan doesn't include API access. You need a Business plan.
- Make sure you're using the right key type:
pk_keys are for the Embed SDK (frontend),sk_keys are for the Server SDK (backend). Mixing them up is the most common mistake. - If you're running against staging or development, set
environment: 'staging'(or'development') on the SDK. keys themselves don't carry an environment flag.
What to do next
Now that the SDKs are installed, pick your next step:
- Quick start. send your first signature request in 10 minutes
- API documentation. full endpoint reference with examples
- SDKs. advanced SDK features and per-framework guides
- Webhooks. set up real-time event notifications
- Security best practices. what to configure before going live
Frequently asked questions
Quick answers to the questions developers ask most often.