Quick start guide
It takes about ten minutes to go from a fresh signup to a signed, blockchain-verified document. There are two ways in: the web app and the API. This guide covers both, so pick the one that matches how you work.
Signing through the web interface
No code required for your first signature request. The web app covers the whole flow: uploading the file, adding recipients, collecting signatures, and writing the blockchain record. If you're curious about the legal backing behind it, that's the eIDAS Regulation.
Before you start
You'll need a Chaindoc account (free plan works). Sign up at app.chaindoc.io. Have a document ready (PDF, DOC, or image) and the email addresses of anyone who needs to sign.
Step-by-step: your first signature
- 1Create your accountSign up at app.chaindoc.io and verify your email. Takes about 30 seconds.
- 2Upload a documentClick "New Document" and drag in your file. Chaindoc supports PDF, Office documents, and images up to 250 MB through the current upload API.
- 3Fill in the detailsGive it a name, add a description if you want, and pick an access level (private, team, or public). Tags are optional but help with search later.
- 4Create a signature requestClick "Request Signatures", add the signer emails, set a deadline, and write a message. All recipients are invited in parallel; sequential and conditional signing orders are not supported yet.
- 5Send itReview the details and hit send. Each recipient gets an email with a secure signing link. You can also enable KYC verification if you need identity checks.
- 6Track progressThe dashboard shows who's signed and who hasn't, in real time. You'll get notified as each signature comes in.
- 7Download the signed copyOnce everyone signs, download the final document. Chaindoc creates a PAdES-signed PDF and a blockchain verification record that proves the signed file hasn't been modified.
That's it
Your document is now blockchain-verified, all parties have signed copies, and there's an immutable audit trail. The whole process typically takes 2-5 minutes once signers open the link.
Want to understand Chaindoc's signature and verification model? The platform focuses on PAdES Advanced Electronic Signatures with blockchain evidence, plus optional KYC for higher-assurance workflows.
Integrating via the API
If you're building signing into your own app, you'll use the REST API and TypeScript SDKs. The flow is the same as the web interface, just automated.
1. Get your API keys
API access requires a Business plan. Go to Settings > API Access in your dashboard and create two keys:
- Public key (
pk_) for frontend use with the Embed SDK - Secret key (
sk_) for backend use with the Server SDK. Keep this one out of client-side code.
2. Install the SDK
Pick the SDK that matches your use case. Most apps need both: the Server SDK for creating documents and the Embed SDK for the signing UI.
# Node.js 18+ required
npm install @chaindoc_io/server-sdkFor detailed framework setup (React, Vue, Angular, Next.js), check the installation guide.
3. Upload and create a document
import { Chaindoc } from '@chaindoc_io/server-sdk';
import { readFile } from 'fs/promises';
// Initialize SDK
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_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 record
const doc = await chaindoc.documents.create({
name: 'Service Agreement',
description: 'Q4 2026 Contract',
media: media[0],
status: 'published', // Triggers blockchain verification
hashtags: ['#contract', '#2026'],
meta: [{ key: 'client', value: 'Acme Corp' }],
});
console.log('Document created:', doc.documentId);Setting status: 'published' triggers blockchain verification automatically. If you want to hold off, use 'draft' and publish later.
4. Create a signature request
// Create signature request for multiple signers
const versionId = doc.document.currentVersion!.id;
const sigRequest = await chaindoc.signatures.createRequest({
versionId,
recipients: [
{ email: 'signer1@example.com' },
{ email: 'signer2@example.com' },
],
deadline: new Date('2026-12-31'),
message: 'Please review and sign this agreement',
embeddedFlow: true, // Enable for frontend integration
});
console.log('Signature request created:', sigRequest.requestId);Set embeddedFlow: true if you're going to show the signing UI inside your app. Without it, signers get a link to Chaindoc's hosted signing page instead.
5. Show the signing interface (frontend)
This is optional. If you set embeddedFlow: true, you can open the signing UI right inside your app. First, create a session on the backend, then pass the session ID to the frontend.
// Create embedded session for signer
const session = await chaindoc.embedded.createSession({
email: 'signer1@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.requestId,
},
});
// Return sessionId to frontend
res.json({ sessionId: session.sessionId });6. Check status and listen for events
For production automation, lean on the signature.request.completed and signature.request.rejected webhooks. Polling the status endpoint is fine for an ad-hoc check, or as a reconciliation fallback when a webhook gets missed.
// Reconciliation check (use webhooks for real-time production automation)
const status = await chaindoc.signatures.getRequestStatus(sigRequest.requestId);
if (status.status === 'completed') {
console.log('All signatures collected!');
}7. Set up webhooks (recommended)
Webhooks push events to your server as they happen, so there's no need to keep polling. Here's a basic Express handler:
import { Chaindoc } from '@chaindoc_io/server-sdk';
import express from 'express';
const app = express();
app.post('/webhooks/chaindoc', express.raw({ type: 'application/json' }), (req, res) => {
const result = Chaindoc.webhooks.verify(
(req.body as Buffer).toString('utf8'),
req.header('X-Chaindoc-Signature') ?? '',
req.header('X-Chaindoc-Timestamp') ?? '',
process.env.CHAINDOC_WEBHOOK_SECRET!,
);
if (!result.valid || !result.envelope) {
return res.status(401).send('Invalid signature');
}
const { type, data } = result.envelope;
switch (type) {
case 'signature.request.completed':
console.log('All signers completed:', data.signatureRequestId);
break;
case 'document.signed':
console.log('Document signed:', data.documentId);
break;
case 'signature.request.rejected':
console.log('Signature request rejected:', data.signatureRequestId);
break;
case 'invoice.paid':
console.log('Invoice paid:', data.invoiceId);
break;
}
res.status(200).send('OK');
});In production, verify the webhook signature before trusting the payload. The Server SDK ships a static helper (Chaindoc.webhooks.verify(rawBody, signature, timestamp, secret)) that handles HMAC-SHA256 and the replay-protection timestamp window for you. Full details in the webhooks guide.
Full workflow example
This puts it all together: upload, create, sign, verify. Copy it, swap in your API keys, and you've got a working prototype.
import { Chaindoc } from '@chaindoc_io/server-sdk';
import { readFile } from 'fs/promises';
async function createSigningWorkflow() {
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// Step 1: Upload document
const buffer = await readFile('./contract.pdf');
const file = new Blob([buffer], { type: 'application/pdf' });
const { media } = await chaindoc.media.upload([file]);
// Step 2: Create document
const doc = await chaindoc.documents.create({
name: 'Service Agreement',
description: 'Contract for consulting services',
media: media[0],
status: 'published',
hashtags: ['#contract'],
meta: [],
});
// Step 3: Create signature request
const sigRequest = await chaindoc.signatures.createRequest({
versionId: doc.document.currentVersion!.id,
recipients: [{ email: 'signer@example.com' }],
deadline: new Date('2026-12-31'),
embeddedFlow: true,
});
// Step 4: Create session for frontend
const session = await chaindoc.embedded.createSession({
email: 'signer@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.requestId,
},
});
return {
documentId: doc.documentId,
sessionId: session.sessionId,
};
}
// Usage
const { documentId, sessionId } = await createSigningWorkflow();
console.log('Ready for signing:', { documentId, sessionId });Where to go next
That covers the basics. Where you go from here depends on what you're building:
- Installation: framework-specific setup for React, Vue, Angular, and Next.js
- API documentation: full endpoint reference with request and response examples
- SDKs: the Server SDK and Embed SDK, with per-framework integration guides
- Webhooks: real-time event notifications for production apps
- Security best practices: what to lock down before you go live
Development tips
Keep separate sk_/pk_ keys for development and production, and point your SDKs at staging with environment: 'staging' while you build. That keeps real users from getting signature emails triggered by your test runs. Store keys in environment variables rather than in source, and start with small files until the flow feels familiar.
Common questions
How long does blockchain verification take?
Usually one to five minutes, depending on network conditions. The document itself is available immediately. Verification runs in the background, and a webhook event fires once it finishes.
Can I test the API without hitting production?
The free plan covers the web interface; API access needs a Business plan. Once you have it, pass environment: 'staging' to the SDK constructor to work against the staging environment. Nothing you do there touches real users or real blockchain traffic.
Are these signatures legally binding?
Yes. Chaindoc signatures comply with eIDAS in Europe, the ESIGN Act and UETA in the US, and equivalent regulations in most other jurisdictions. The blockchain verification adds an extra layer of evidence on top of that, which can matter in disputes. See the signatures docs for details on which signature type fits your compliance needs.
What file formats can I upload?
PDF, DOC, DOCX, XLS, XLSX, PPT, PPTX, TXT, JPG, PNG, GIF, WEBP, SVG, MP4, AVI, MOV, and WMV. The current upload API accepts files up to 250 MB.
Frequently asked questions
Quick answers to the questions developers ask most often.