SDK Chaindoc

SDK officiels pour une intégration Chaindoc sans problème. Prise en charge complète de TypeScript, aucune dépendance et conception indépendante du framework pour les applications backend et frontend.

SDK disponibles

  • Server SDK (@chaindoc_io/server-sdk) - Intégration backend pour Node.js 18+
  • SDK intégré (@chaindoc_io/embed-sdk) - Interface de signature frontale pour les applications web
  • SDK Python - À venir bientôt
  • SDK PHP - À venir

SDK serveur

Le SDK serveur offre une interface Node.js sécurisée pour l'API Chaindoc. Utilise-le pour gérer des documents, créer des demandes de signature, gérer les téléchargements de fichiers et intégrer la vérification blockchain dans ton backend.

Installation

npm install @chaindoc_io/server-sdk

Démarrage rapide

server.ts
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

server.ts
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

app/api/signing/create-session/route.ts
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 traitez spécifiquement les ChaindocError :

terminal
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;
    }
  }
}

Intégrer le SDK

Le SDK Embed permet d'intégrer facilement la fonctionnalité de signature de documents dans les applications web. Il gère un flux de signature basé sur iframe avec une communication sécurisée entre ton application et Chaindoc.

Installation

npm install @chaindoc_io/embed-sdk

Utilisation de base

terminal
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

composants/SignButton.tsx
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 de Vue 3

SignButton.vue
<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 en ligne

Au lieu d'une fenêtre modale, mets l'interface de signature directement dans ta page :

terminal
const instance = chaindoc.openSignatureFlow({
  sessionId,
  mode: 'inline',
  container: document.getElementById('signature-container'),
  
  onSuccess: (data) => {
    console.log('Signed!');
  },
});

Thèmes

Personnalisez l'apparence avec des thèmes clairs ou sombres :

terminal
const instance = chaindoc.openSignatureFlow({
  sessionId,
  theme: 'dark',
  // ... other options
});

// Change theme dynamically
instance.changeTheme('light');

Exemple complet de flux de travail

Voici un exemple complet de bout en bout combinant le SDK serveur et le SDK d'intégration :

1Backend : Télécharger le documentUtilise le SDK serveur pour télécharger le fichier et créer le document.

2Backend : créer une demande de signatureCrée une demande de signature avec le flux intégré activé.

3Backend : Générer une sessionCrée une session intégrée pour chaque signataire.

4Frontend : lance le SDK EmbedLance le SDK avec la clé publique.

5Frontend : ouvrir le flux de signatureOuvrez l'interface de signature avec l'ID de session.

6Frontend : gérer le succèsTraite le document signé et mets à jour l'interface utilisateur.

// 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

  • Lance le SDK une fois par page/composant.
  • Toujours détruire l'instance SDK lors du démontage du composant.
  • Gère tous les événements de rappel (onSuccess, onError, onCancel).
  • Stockez les clés API dans des variables d'environnement.
  • Utilise TypeScript pour une meilleure sécurité des types.
  • Mets en place une gestion correcte des erreurs avec ChaindocError.
  • Teste avec des clés sandbox avant de passer en production.

Configuration de l'environnement

// Backend
const chaindoc = new Chaindoc({
  secretKey: 'sk_live_xxxxx',
});

// Frontend
const embed = new ChaindocEmbed({
  publicKey: 'pk_live_xxxxx',
  environment: 'production',
});