Chaindoc SDK
Ecco la cosa: Chaindoc offre due SDK TypeScript pensati per esigenze diverse. Il Server SDK gestisce il backend (Node.js), mentre l'Embed SDK ti permette di integrare l'interfaccia di firma direttamente nella tua web app. Entrambi includono definizioni di tipo complete, zero dipendenze runtime e funzionano con qualsiasi framework.
SDK Disponibili
Per la configurazione npm e le impostazioni specifiche per framework (variabili d'ambiente, provider, ecc.), consulta la guida all'installazione.
- Server SDK (@chaindoc_io/server-sdk) - Integrazione backend per Node.js 18+
- Embed SDK (@chaindoc_io/embed-sdk) - Interfaccia di firma frontend per applicazioni web
- Python SDK - In arrivo
- PHP SDK - In arrivo
Server SDK
Il Server SDK avvolge la REST API in un'interfaccia Node.js type-safe. Lo usi per gestire documenti, creare richieste di firma, gestire upload di file e attivare la verifica blockchain.
Installazione
npm install @chaindoc_io/server-sdkAvvio rapido
import { Chaindoc } from '@chaindoc_io/server-sdk';
import { readFile } from 'fs/promises';
// 1. Inizializza l'SDK
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// 2. Carica un file documento
const buffer = await readFile('./contract.pdf');
const file = new Blob([buffer], { type: 'application/pdf' });
const { media } = await chaindoc.media.upload([file]);
// 3. Crea un documento
const doc = await chaindoc.documents.create({
name: 'Service Agreement',
description: 'Contract for consulting services',
media: media[0],
status: 'published', // Attiva la verifica blockchain
hashtags: ['#contract', '#2024'],
meta: [{ key: 'client', value: 'Acme Corp' }],
});
// 4. Crea una richiesta di firma
const sigRequest = await chaindoc.signatures.createRequest({
versionId: doc.document.versions[0].uuid,
recipients: [{ email: 'signer@example.com' }],
deadline: new Date('2024-12-31'),
embeddedFlow: true,
});
// 5. Crea sessione per l'SDK frontend
const session = await chaindoc.embedded.createSession({
email: 'signer@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.signatureRequest.uuid,
},
});
console.log('Session ID:', session.sessionId);Integrazione Express.js
import express from 'express';
import { Chaindoc, ChaindocError } from '@chaindoc_io/server-sdk';
import multer from 'multer';
const app = express();
const upload = multer({ storage: multer.memoryStorage() });
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// Carica e crea documento
app.post('/api/documents', upload.single('file'), async (req, res) => {
try {
const file = new Blob([req.file!.buffer], { type: req.file!.mimetype });
const { media } = await chaindoc.media.upload([file]);
const doc = await chaindoc.documents.create({
name: req.body.name,
description: req.body.description || '',
media: media[0],
status: 'published',
hashtags: req.body.hashtags || [],
meta: req.body.meta || [],
});
res.json({ documentId: doc.documentId });
} catch (error) {
if (error instanceof ChaindocError) {
res.status(error.statusCode || 500).json({ error: error.message });
} else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// Crea sessione embedded per firmatario
app.post('/api/signing/session', async (req, res) => {
try {
const { email, documentId, signatureRequestId } = req.body;
const session = await chaindoc.embedded.createSession({
email,
metadata: { documentId, signatureRequestId },
});
res.json({ sessionId: session.sessionId });
} catch (error) {
if (error instanceof ChaindocError) {
res.status(error.statusCode || 500).json({ error: error.message });
}
}
});
app.listen(3000);Route API Next.js
import { NextRequest, NextResponse } from 'next/server';
import { Chaindoc, ChaindocError } from '@chaindoc_io/server-sdk';
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
export async function POST(request: NextRequest) {
try {
const { email, documentId, signatureRequestId } = await request.json();
const session = await chaindoc.embedded.createSession({
email,
metadata: { documentId, signatureRequestId },
});
return NextResponse.json({
sessionId: session.sessionId,
expiresAt: session.expiresAt,
});
} catch (error) {
if (error instanceof ChaindocError) {
return NextResponse.json(
{ error: error.message },
{ status: error.statusCode || 500 }
);
}
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}Gestione errori
Onestamente, dovresti sempre racchiudere le chiamate API in blocchi try-catch e gestire ChaindocError in modo specifico:
import { ChaindocError } from '@chaindoc_io/server-sdk';
try {
const doc = await chaindoc.documents.create({ /* ... */ });
} catch (error) {
if (error instanceof ChaindocError) {
console.error('API Error:', error.message);
console.error('Status Code:', error.statusCode);
switch (error.statusCode) {
case 400:
// Bad request - verifica i parametri
break;
case 401:
// Unauthorized - controlla la chiave API
break;
case 404:
// Not found
break;
case 429:
// Rate limited - l'SDK riproverà automaticamente
break;
}
}
}Embed SDK
L'Embed SDK ti permette di mostrare l'interfaccia di firma Chaindoc direttamente nella tua app. Gestisce l'iframe, la verifica OTP e la comunicazione tra la tua app e Chaindoc. I tuoi utenti firmano documenti senza mai uscire dal tuo sito.
Installazione
npm install @chaindoc_io/embed-sdkUtilizzo base
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
// 1. Inizializza l'SDK (una volta per pagina)
const chaindoc = new ChaindocEmbed({
publicKey: 'pk_live_xxxxxxxxxxxxx',
environment: 'production',
});
// 2. Ottieni sessione dal tuo backend
const response = await fetch('/api/signing/create-session', {
method: 'POST',
body: JSON.stringify({ documentId, signerEmail }),
});
const { sessionId } = await response.json();
// 3. Apri flusso di firma
const instance = chaindoc.openSignatureFlow({
sessionId,
onReady: () => {
console.log('Interfaccia di firma caricata');
},
onSuccess: (data) => {
console.log('Documento firmato:', data.signatureId);
instance.close();
},
onError: (error) => {
console.error('Firma fallita:', error.code, error.message);
},
onCancel: () => {
console.log('Utente annullato');
instance.close();
},
});Integrazione React
import { useCallback, useRef, useEffect } from 'react';
import { ChaindocEmbed, EmbedInstance } from '@chaindoc_io/embed-sdk';
function SignButton({ sessionId }: { sessionId: string }) {
const sdkRef = useRef<ChaindocEmbed | null>(null);
const instanceRef = useRef<EmbedInstance | null>(null);
useEffect(() => {
sdkRef.current = new ChaindocEmbed({
publicKey: process.env.REACT_APP_CHAINDOC_PUBLIC_KEY!,
});
return () => {
sdkRef.current?.destroy();
};
}, []);
const handleSign = useCallback(() => {
if (!sdkRef.current) return;
instanceRef.current = sdkRef.current.openSignatureFlow({
sessionId,
onSuccess: (data) => {
console.log('Firmato!', data.signatureId);
instanceRef.current?.close();
},
onCancel: () => {
instanceRef.current?.close();
},
});
}, [sessionId]);
return <button onClick={handleSign}>Firma Documento</button>;
}Integrazione Vue 3
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ChaindocEmbed, type EmbedInstance } from '@chaindoc_io/embed-sdk';
const props = defineProps<{ sessionId: string }>();
let sdk: ChaindocEmbed | null = null;
let instance: EmbedInstance | null = null;
onMounted(() => {
sdk = new ChaindocEmbed({
publicKey: import.meta.env.VITE_CHAINDOC_PUBLIC_KEY,
});
});
onUnmounted(() => {
sdk?.destroy();
});
function openSignature() {
if (!sdk) return;
instance = sdk.openSignatureFlow({
sessionId: props.sessionId,
onSuccess: (data) => {
console.log('Firmato!', data.signatureId);
instance?.close();
},
onCancel: () => {
instance?.close();
},
});
}
</script>
<template>
<button @click="openSignature">Firma Documento</button>
</template>Modalità inline
In pratica, puoi incorporare l'interfaccia di firma direttamente nella pagina invece di usare un modal:
const instance = chaindoc.openSignatureFlow({
sessionId,
mode: 'inline',
container: document.getElementById('signature-container'),
onSuccess: (data) => {
console.log('Firmato!');
},
});Temi
Personalizza l'aspetto con temi chiaro o scuro:
const instance = chaindoc.openSignatureFlow({
sessionId,
theme: 'dark',
// ... altre opzioni
});
// Cambia tema dinamicamente
instance.changeTheme('light');Esempio flusso completo
L'essenziale è questo: Server SDK sul backend per creare documenti e sessioni, Embed SDK sul frontend per mostrare l'interfaccia di firma.
1Backend: Carica DocumentoUsa Server SDK per caricare file e creare documento
2Backend: Crea Richiesta di FirmaCrea richiesta firma con flusso embedded abilitato
3Backend: Genera SessioneCrea sessione embedded per ogni firmatario
4Frontend: Inizializza Embed SDKInizializza SDK con chiave pubblica
5Frontend: Apri Flusso di FirmaApri interfaccia firma con session ID
6Frontend: Gestisci SuccessoProcessa documento firmato e aggiorna UI
// server.ts
import { Chaindoc } from '@chaindoc_io/server-sdk';
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// Carica e crea documento
const { media } = await chaindoc.media.upload([pdfFile]);
const doc = await chaindoc.documents.create({
name: 'Contract',
description: 'Service agreement',
media: media[0],
status: 'published',
hashtags: ['#contract'],
meta: [],
});
// Crea richiesta firma
const sigRequest = await chaindoc.signatures.createRequest({
versionId: doc.document.versions[0].uuid,
recipients: [{ email: 'signer@example.com' }],
deadline: new Date('2024-12-31'),
embeddedFlow: true,
});
// Crea sessione
const session = await chaindoc.embedded.createSession({
email: 'signer@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.signatureRequest.uuid,
},
});
// Restituisci sessionId al frontend
res.json({ sessionId: session.sessionId });Best practices
- Inizializza l'SDK una sola volta per ciclo di vita pagina/componente
- Distruggi sempre l'istanza SDK al smontaggio del componente
- Gestisci tutti i callback (onSuccess, onError, onCancel)
- Memorizza le chiavi API in variabili d'ambiente
- Usa TypeScript per maggiore type safety
- Implementa gestione errori appropriata con ChaindocError
- Testa con chiavi sandbox prima del deploy in produzione
Configurazione ambiente
// Backend
const chaindoc = new Chaindoc({
secretKey: 'sk_live_xxxxx',
});
// Frontend
const embed = new ChaindocEmbed({
publicKey: 'pk_live_xxxxx',
environment: 'production',
});Cosa fare dopo
- Installazione — setup npm, config env e provider specifici per framework
- Documentazione API — riferimento completo endpoint REST
- Webhooks — notifiche eventi real-time per il tuo backend
- Avvio rapido — invia la tua prima firma in 10 minuti
- Sicurezza — gestione chiavi API e hardening produzione