SDKs Chaindoc
Chaindoc propose deux SDKs TypeScript : le Server SDK pour le backend (Node.js) et l'Embed SDK pour intégrer une interface de signature dans votre app web. Les deux incluent des définitions de types complètes, zéro dépendance runtime, et fonctionnent avec n'importe quel framework.
SDKs disponibles
Pour la configuration npm et les spécificités frameworks (variables d'env, providers, etc.), consultez le guide d'installation.
- Server SDK (@chaindoc_io/server-sdk) - Intégration backend pour Node.js 18+
- Embed SDK (@chaindoc_io/embed-sdk) - Interface de signature frontend pour applications web
- Python SDK - Bientôt disponible
- PHP SDK - Bientôt disponible
Server SDK
Le Server SDK encapsule l'API REST dans une interface Node.js type-safe. Il sert à gérer les documents, créer des demandes de signature, gérer les uploads de fichiers et déclencher la vérification blockchain.
Installation
npm install @chaindoc_io/server-sdkDémarrage rapide
import { Chaindoc } from '@chaindoc_io/server-sdk';
import { readFile } from 'fs/promises';
// 1. Initialize the SDK
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// 2. Upload a document file
const buffer = await readFile('./contract.pdf');
const file = new Blob([buffer], { type: 'application/pdf' });
const { media } = await chaindoc.media.upload([file]);
// 3. Create a document
const doc = await chaindoc.documents.create({
name: 'Service Agreement',
description: 'Contract for consulting services',
media: media[0],
status: 'published', // Triggers blockchain verification
hashtags: ['#contract', '#2024'],
meta: [{ key: 'client', value: 'Acme Corp' }],
});
// 4. Create a signature request
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. Create session for frontend SDK
const session = await chaindoc.embedded.createSession({
email: 'signer@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.signatureRequest.uuid,
},
});
console.log('Session ID:', session.sessionId);Intégration 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!,
});
// Upload and create document
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' });
}
}
});
// Create embedded session for signer
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);Routes 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 }
);
}
}Gestion des erreurs
Enveloppez toujours les appels API dans des blocs try-catch et gérez spécifiquement ChaindocError :
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 - check parameters
break;
case 401:
// Unauthorized - check API key
break;
case 404:
// Not found
break;
case 429:
// Rate limited - SDK will auto-retry
break;
}
}
}Embed SDK
L'Embed SDK permet d'afficher l'interface de signature Chaindoc directement dans votre app. Il gère l'iframe, la vérification OTP et la communication entre votre app et Chaindoc. Vos utilisateurs signent sans quitter votre site.
Installation
npm install @chaindoc_io/embed-sdkUtilisation basique
import { ChaindocEmbed } from '@chaindoc_io/embed-sdk';
// 1. Initialize SDK (once per page)
const chaindoc = new ChaindocEmbed({
publicKey: 'pk_live_xxxxxxxxxxxxx',
environment: 'production',
});
// 2. Get session from your backend
const response = await fetch('/api/signing/create-session', {
method: 'POST',
body: JSON.stringify({ documentId, signerEmail }),
});
const { sessionId } = await response.json();
// 3. Open signing flow
const instance = chaindoc.openSignatureFlow({
sessionId,
onReady: () => {
console.log('Signing interface loaded');
},
onSuccess: (data) => {
console.log('Document signed:', data.signatureId);
instance.close();
},
onError: (error) => {
console.error('Signing failed:', error.code, error.message);
},
onCancel: () => {
console.log('User cancelled');
instance.close();
},
});Intégration 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('Signed!', data.signatureId);
instanceRef.current?.close();
},
onCancel: () => {
instanceRef.current?.close();
},
});
}, [sessionId]);
return <button onClick={handleSign}>Sign Document</button>;
}Intégration 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('Signed!', data.signatureId);
instance?.close();
},
onCancel: () => {
instance?.close();
},
});
}
</script>
<template>
<button @click="openSignature">Sign Document</button>
</template>Mode inline
Au lieu d'une modal, intégrez l'interface de signature directement dans votre page :
const instance = chaindoc.openSignatureFlow({
sessionId,
mode: 'inline',
container: document.getElementById('signature-container'),
onSuccess: (data) => {
console.log('Signed!');
},
});Thèmes
Personnalisez l'apparence avec les thèmes clair ou sombre :
const instance = chaindoc.openSignatureFlow({
sessionId,
theme: 'dark',
// ... other options
});
// Change theme dynamically
instance.changeTheme('light');Exemple complet de workflow
Voici le truc : on combine les deux SDKs. Le Server SDK côté backend pour créer documents et sessions, l'Embed SDK côté frontend pour afficher l'interface de signature.
1Backend: Uploader le documentUtiliser Server SDK pour uploader le fichier et créer le document
2Backend: Créer la demande de signatureCréer une demande de signature avec le flux intégré activé
3Backend: Générer la sessionCréer une session intégrée pour chaque signataire
4Frontend: Initialiser Embed SDKInitialiser le SDK avec la clé publique
5Frontend: Ouvrir le flux de signatureOuvrir l'interface de signature avec l'ID de session
6Frontend: Gérer le succèsTraiter le document signé et mettre à jour l'UI
// server.ts
import { Chaindoc } from '@chaindoc_io/server-sdk';
const chaindoc = new Chaindoc({
secretKey: process.env.CHAINDOC_SECRET_KEY!,
});
// Upload & create document
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: [],
});
// Create signature request
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,
});
// Create session
const session = await chaindoc.embedded.createSession({
email: 'signer@example.com',
metadata: {
documentId: doc.documentId,
signatureRequestId: sigRequest.signatureRequest.uuid,
},
});
// Return sessionId to frontend
res.json({ sessionId: session.sessionId });Bonnes pratiques
- Initialisez le SDK une fois par cycle de vie page/composant
- Détruisez toujours l'instance SDK au démontage du composant
- Gérez tous les événements callback (onSuccess, onError, onCancel)
- Stockez les clés API dans les variables d'environnement
- Utilisez TypeScript pour une meilleure sécurité de types
- Implémentez une gestion d'erreur appropriée avec ChaindocError
- Testez avec les clés sandbox avant le déploiement production
Configuration environnement
// Backend
const chaindoc = new Chaindoc({
secretKey: 'sk_live_xxxxx',
});
// Frontend
const embed = new ChaindocEmbed({
publicKey: 'pk_live_xxxxx',
environment: 'production',
});Et ensuite ?
- Installation — Setup npm, config env, et providers spécifiques frameworks
- Documentation API — Référence complète des endpoints REST
- Webhooks — Notifications d'événements temps réel pour votre backend
- Démarrage rapide — Envoyez votre première signature en 10 minutes
- Sécurité — Gestion des clés API et hardening production