npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@fiscapi-node/sdk

v1.1.0

Published

SDK officiel Node.js/TypeScript pour l'API FiscAPI - Facturation e-MECeF au Bénin

Readme

FiscAPI SDK pour Node.js

SDK officiel pour l'intégration de la facturation e-MECeF (DGI Bénin) avec FiscAPI.

npm version

✨ Nouveautés v1.1.0

  • ✅ Support complet des avoirs (FA/EA)
  • ✅ Endpoint de normalisation des brouillons
  • ✅ Authentification via header x-api-key
  • ✅ Support des réponses paginées
  • ✅ Calcul TVA côté client

📦 Installation

npm install @fiscapi-node/sdk
# ou
yarn add @fiscapi-node/sdk

🔐 Sécurité - IMPORTANT

⚠️ NE JAMAIS exposer votre clé API côté client

// ❌ DANGEREUX - La clé est visible dans le code source
const fiscapi = new FiscApi('sk_live_xxx'); // Dans le navigateur = FUITE

✅ Utilisez TOUJOURS le SDK côté serveur

| Architecture | Sécurité | Recommandation | |--------------|----------|----------------| | Node.js / Backend | ✅ Sécurisé | ✅ Recommandé | | Serverless (Vercel, Netlify) | ✅ Sécurisé | ✅ Recommandé | | Frontend (React, Vue, etc.) | ❌ Dangereux | ❌ À éviter | | Mobile (React Native, Flutter) | ❌ Dangereux | ❌ À éviter |

Architecture recommandée

┌─────────────────┐     ┌─────────────────┐     ┌────────────────┐
│  Votre Frontend │ --> │  Votre Backend  │ --> │   FiscAPI v1   │
│  (React, Vue)   │     │  (Node, Python) │     │ (clé API ici)  │
└─────────────────┘     └─────────────────┘     └────────────────┘
        ▲                       │
        │                       │
    Sans clé              Clé API en
    (session)             variable env

Variables d'environnement

# .env (jamais commité)
FISCAPI_API_KEY=sk_live_xxx

# .env.example (à committer)
FISCAPI_API_KEY=
// Charger la clé depuis l'environnement
const fiscapi = new FiscApi(process.env.FISCAPI_API_KEY!);

🚀 Démarrage rapide

import { FiscApi } from '@fiscapi-node/sdk';

// Initialiser avec votre clé API (côté serveur uniquement)
const fiscapi = new FiscApi(process.env.FISCAPI_API_KEY!);

// Créer et normaliser une facture
const invoice = await fiscapi.invoices.create({
  type: 'FV',                    // FV = Facture de Vente
  items: [
    { 
      name: 'Consultation', 
      price: 50000,              // Prix TTC
      quantity: 1, 
      taxGroup: 'B'              // B = TVA 18%
    }
  ],
  client: { 
    name: 'SARL Example',
    ifu: '0101010101010'         // Optionnel
  }
});

// Récupérer les données de sécurité DGI
console.log(invoice.status);                   // 'CONFIRMED'
console.log(invoice.security?.codeMECeFDGI);   // 'TEST-XXXX-YYYY-ZZZZ'
console.log(invoice.security?.qrCode);         // QR code à imprimer
console.log(invoice.security?.nim);            // NIM de la machine
console.log(invoice.totals.total);             // 50000
console.log(invoice.totals.totalTVA);          // 7627

📋 Format de requête (Format DGI)

interface CreateInvoicePayload {
  // Type de facture
  type: 'FV' | 'FA' | 'EV' | 'EA';  // FV=Vente, FA=Avoir, EV=Export, EA=Avoir Export
  
  // AIB (Acompte Impôt Bénéfice)
  aib?: 'A' | 'B' | null;           // A=1%, B=5%, null=pas d'AIB
  
  // Client (optionnel pour vente au comptoir)
  client?: {
    name: string;                    // Nom (min 5 caractères)
    ifu?: string;                    // IFU 13 chiffres
    contact?: string;                // Téléphone
    address?: string;                // Adresse
  };
  
  // Articles
  items: Array<{
    name: string;                    // Désignation
    price: number;                   // Prix unitaire
    quantity: number;                // Quantité
    taxGroup: 'A'|'B'|'C'|'D'|'E'|'F';
    taxSpecific?: number;            // Taxe spécifique par unité
  }>;
  
  // Paiements
  payment?: Array<{
    name: 'ESPECES' | 'VIREMENT' | 'CARTEBANCAIRE' | 'MOBILEMONEY';
    amount: number;
  }>;
  
  // Options
  pricingMode?: 'HT' | 'TTC';        // Défaut: TTC
  autoNormalize?: boolean;            // Défaut: true
  reference?: string;                 // Pour avoirs FA/EA
}

📊 Groupes de taxes

| Code | Nom | Taux | Description | |------|-----|------|-------------| | A | Exonéré | 0% | Produits exonérés de TVA | | B | Taxable | 18% | TVA standard | | C | Exportation | 0% | Vente à l'export | | D | Exception | 0% | Régime d'exception | | E | TPS | 0% | Taxe Professionnelle Synthétique | | F | Spécifique | 0% | Taxe spécifique uniquement |


📝 Exemples

Facture simple (FV)

const invoice = await fiscapi.invoices.create({
  type: 'FV',
  client: { name: 'Client Simple' },
  items: [
    { name: 'Consultation', price: 50000, quantity: 1, taxGroup: 'B' }
  ]
});

console.log(invoice.status);                  // 'CONFIRMED'
console.log(invoice.security?.codeMECeFDGI);  // 'TEST-XXXX-...'

Facture multi-lignes

const invoice = await fiscapi.invoices.create({
  type: 'FV',
  client: {
    name: 'Entreprise ABC',
    ifu: '0101010101010',
    contact: '+229 97 00 00 00',
    address: 'Cotonou, Bénin'
  },
  items: [
    { name: 'Ordinateur portable', price: 350000, quantity: 2, taxGroup: 'B' },
    { name: 'Souris sans fil', price: 15000, quantity: 5, taxGroup: 'B' },
    { name: 'Câble HDMI', price: 5000, quantity: 3, taxGroup: 'A' }  // Exonéré
  ]
});

Facture avec AIB

const invoice = await fiscapi.invoices.create({
  type: 'FV',
  aib: 'A',  // 1% du montant
  client: {
    name: 'Client avec AIB',
    ifu: '0202020202020'
  },
  items: [
    { name: 'Prestation de services', price: 100000, quantity: 1, taxGroup: 'B' }
  ]
});

console.log(invoice.totals.aib);  // Montant AIB (1000 FCFA)

Facture d'exportation (EV)

const invoice = await fiscapi.invoices.create({
  type: 'EV',
  client: {
    name: 'Client Export International',
    address: 'Paris, France'
  },
  items: [
    { name: 'Noix de cajou (export)', price: 500000, quantity: 10, taxGroup: 'C' },
    { name: 'Karité brut (export)', price: 250000, quantity: 5, taxGroup: 'C' }
  ]
});

console.log(invoice.totals.totalTVA);  // 0 (pas de TVA à l'export)

Mode HT (prix hors taxes)

const invoice = await fiscapi.invoices.create({
  type: 'FV',
  pricingMode: 'HT',  // Prix hors taxes
  client: { name: 'Client HT' },
  items: [
    { name: 'Service', price: 10000, quantity: 1, taxGroup: 'B' }
  ]
});

// Le SDK calcule automatiquement la TVA
console.log(invoice.totals.totalHT);   // 10000
console.log(invoice.totals.totalTVA);  // 1800
console.log(invoice.totals.total);     // 11800

💳 Avoirs (Remboursements)

Avoir total (remboursement complet)

// Créer d'abord une facture
const invoice = await fiscapi.invoices.create({
  type: 'FV',
  client: { name: 'Client à rembourser' },
  items: [
    { name: 'Produit', price: 30000, quantity: 1, taxGroup: 'B' }
  ]
});

// Attendre 4 secondes pour la prise en compte DGI
await new Promise(resolve => setTimeout(resolve, 4000));

// Créer l'avoir total
const creditNote = await fiscapi.invoices.refund(invoice.uid, 'Annulation commande');

console.log(creditNote.type);                    // 'FA'
console.log(creditNote.status);                  // 'CONFIRMED'
console.log(creditNote.security?.codeMECeFDGI);  // Code de l'avoir

Avoir partiel (remboursement sélectif)

// Rembourser 2 unités de la ligne 1
const creditNote = await fiscapi.invoices.refundPartial('clx123abc', {
  lines: [
    { position: 1, quantity: 2 },  // Ligne 1, 2 unités
    { position: 3 },                // Ligne 3 entière
  ],
  reason: 'Retour produit défectueux'
});

📄 Brouillons

Créer un brouillon (sans normaliser)

const draft = await fiscapi.invoices.createDraft({
  type: 'FV',
  items: [{ name: 'Test', price: 25000, quantity: 2, taxGroup: 'B' }],
  client: { name: 'Client Draft' }
});

console.log(draft.status);  // 'DRAFT'

Normaliser le brouillon plus tard

const confirmed = await fiscapi.invoices.normalize(draft.uid);
console.log(confirmed.status);                   // 'CONFIRMED'
console.log(confirmed.security?.codeMECeFDGI);   // Code MECeF

⚠️ Gestion des erreurs

import { FiscApiError } from '@fiscapi-node/sdk';

try {
  const invoice = await fiscapi.invoices.create({ ... });
} catch (error) {
  if (error instanceof FiscApiError) {
    console.error('Code:', error.code);      // 'VALIDATION_ERROR'
    console.error('Message:', error.message);
    console.error('Status:', error.status);  // 422
    console.error('Details:', error.details);
    
    // Codes d'erreur possibles
    switch (error.code) {
      case 'VALIDATION_ERROR':
        // Payload invalide
        break;
      case 'INSUFFICIENT_CREDITS':
        // Pas assez de crédits
        break;
      case 'NORMALIZATION_ERROR':
        // Erreur e-MCF (rejet DGI)
        break;
      case 'UNAUTHORIZED':
        // Clé API invalide
        break;
    }
  }
}

🛠 Utilitaires

Calculer la TVA (synchrone)

// Calculer à partir du TTC
const result = fiscapi.taxGroups.calculateVat(11800, 'B', 'TTC');
console.log(result);  // { ht: 10000, tax: 1800, ttc: 11800 }

// Calculer à partir du HT
const result2 = fiscapi.taxGroups.calculateVat(10000, 'B', 'HT');
console.log(result2);  // { ht: 10000, tax: 1800, ttc: 11800 }

// Exonéré
const result3 = fiscapi.taxGroups.calculateVat(50000, 'A', 'TTC');
console.log(result3);  // { ht: 50000, tax: 0, ttc: 50000 }

Vérifier les crédits

const balance = await fiscapi.credits.getBalance();
console.log(`Crédits: ${balance.available}/${balance.total}`);

if (balance.isLow) {
  console.warn('Solde bas ! Rechargez vos crédits.');
}

// Vérifier avant un batch
const canProcess = await fiscapi.credits.hasSufficientBalance(100);

Vérifier la connexion

const isHealthy = await fiscapi.ping();
if (!isHealthy) {
  console.error('API FiscAPI indisponible');
}

Lister les factures avec pagination

const { data: invoices, count } = await fiscapi.invoices.list({
  limit: 20,
  status: 'CONFIRMED'
});

console.log(`${count} factures trouvées`);
invoices.forEach(inv => console.log(inv.uid, inv.status));

⚙️ Configuration avancée

const fiscapi = new FiscApi({
  apiKey: process.env.FISCAPI_API_KEY!,
  baseUrl: 'https://api.fiscapi.com',  // Optionnel
  timeout: 30000,                       // Optionnel (ms)
});

🔄 Polling (attente de confirmation)

// Attendre qu'une facture soit confirmée
const confirmed = await fiscapi.invoices.waitForConfirmation('clx123abc', {
  maxAttempts: 30,  // Défaut: 30
  intervalMs: 1000, // Défaut: 1000ms
});

📚 API Reference

fiscapi.invoices

| Méthode | Description | |---------|-------------| | create(payload) | Créer et normaliser une facture | | createDraft(payload) | Créer un brouillon | | get(id) | Récupérer une facture | | list(filters?) | Lister les factures (paginé) | | normalize(id) | Normaliser un brouillon | | refund(id, reason?) | Avoir total | | refundPartial(id, options) | Avoir partiel | | isConfirmed(id) | Vérifier si confirmée | | waitForConfirmation(id, options?) | Polling | | getPdfUrl(id) | URL du PDF |

fiscapi.credits

| Méthode | Description | |---------|-------------| | getBalance() | Solde de crédits | | hasSufficientBalance(n) | Vérifier solde suffisant | | listPacks() | Packs disponibles |

fiscapi.fiscalProfiles

| Méthode | Description | |---------|-------------| | list() | Lister les profils | | get(id) | Récupérer un profil | | hasValidToken(id) | Token e-MCF valide ? |

fiscapi.taxGroups

| Méthode | Description | |---------|-------------| | list() | Tous les groupes | | get(code) | Infos d'un groupe | | calculateVat(amount, taxGroup, mode) | Calculer TVA |


🧪 Tests effectués

Le SDK a été testé avec succès pour :

  • ✅ Facture de Vente simple (FV)
  • ✅ Facture multi-lignes avec TVA mixte
  • ✅ Facture avec AIB (1% et 5%)
  • ✅ Facture d'Exportation (EV)
  • ✅ Création et normalisation de brouillons
  • ✅ Avoir total (FA) avec code MECeF
  • ✅ Mode de tarification HT et TTC
  • ✅ Calculs TVA synchrones

🆘 Support

  • 📖 Documentation: https://fiscapi.com/developers
  • 📧 Email: [email protected]
  • 🖥️ Dashboard: https://fiscapi.com/dashboard

📄 Licence

MIT