FR
ConnexionCommencer
Guide du développeur

Intégration API et webhooks Scanee

Le guide d'implémentation pas à pas pour connecter vos systèmes et votre ERP

20 min de lecture Télécharger le PDF
Écouter la conversation

Deux voix de synthèse expliquent ce document, question par question.

0:00 3:12
La conversation0:00 / 3:12

Périmètre

Ce guide couvre l’API d’ingestion et les webhooks sortants. Les exemples utilisent des clés de la forme scanee_... et les espaces réservés <workspace> et <projet> : remplacez-les par les valeurs de l’onglet « Réception » de votre projet.

En bref

  • Chaque projet est un silo : sa clé d’API, ses champs, ses webhooks, son adresse de capture.
  • Vous envoyez un document à l’adresse du projet. Scanee répond tout de suite par 202 Accepted, avant l’extraction.
  • Scanee extrait les champs définis dans le projet, puis pousse le résultat vers votre webhook au statut que vous choisissez.
  • Six formats acceptés, 25 Mo par fichier, 25 documents par requête.

1. L’isolation stricte par projet

Dans Scanee, tout commence par la création d’un projet : « Factures fournisseurs », « Bons de commande », « Notes de frais », « Relevés bancaires ». Chaque projet est un silo autonome, avec sa propre configuration.

Ce qui est propre à chaque projetDétail
Un point d’entrée HTTPhttps://<workspace>.docs.scanee.ai/<projet>/ingest, construit à partir du sigle du projet
Ses clés d’APIUne clé peut être restreinte à un seul projet. Une clé du projet « Factures » ne peut pas déposer de document dans « Notes de frais » : la requête est rejetée en 403 KEY_PROJECT_MISMATCH
Son schéma de donnéesLes champs à extraire : texte, montants, dates, listes, tableaux sur plusieurs pages
Sa consigne IADes directives métier en langage naturel, par exemple les règles fiscales québécoises pour un projet et ontariennes pour un autre
Ses webhooks et ses correspondances d’exportOù envoyer les données, avec quel schéma JSON et quelle authentification
Son adresse de capture par courrielSa propre adresse et sa liste d’expéditeurs approuvés

À retenir. Un projet, c’est une clé, un schéma, un webhook et une adresse de capture. Rien ne traverse la frontière du projet.

2. Le principe : trois temps

Scanee fonctionne en boucle asynchrone : votre système n’attend pas la fin de l’extraction, il est rappelé quand elle est faite.

TempsQuiQuoi
1Votre système (ERP, script, application)Envoie le fichier à l’adresse du projet : fichier, URL ou base64
2Le projet ScaneeExtrait les données selon les champs configurés
3Votre serveur (API, Zapier, Make, base de données)Reçoit le JSON et les liens signés du fichier, au statut choisi

La mise en œuvre tient en cinq étapes : récupérer l’URL et la clé (section 3), envoyer un document (section 4), configurer les champs (section 5), recevoir les données (section 6), gérer les erreurs (section 7).

3. Étape 1 : récupérer votre URL et votre clé d’API

  1. Ouvrez votre projet dans Scanee, puis l’onglet « Réception ».

  2. Vous y trouvez l’URL d’ingestion de votre projet :

    https://<votre-workspace>.docs.scanee.ai/<votre-projet>/ingest

    Exemple : https://acme.docs.scanee.ai/factures/ingest. L’alias /documents fonctionne aussi à la place de /ingest.

  3. Cliquez sur « Créer une clé API », donnez-lui un libellé (par exemple ERP-Prod) et copiez le jeton généré (format scanee_...).

  4. Fournissez cette clé dans chaque requête, avec l’un de ces deux en-têtes :

    X-API-Key: scanee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Authorization: Bearer scanee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Traitez la clé comme un mot de passe : gardez-la côté serveur, jamais dans une application mobile ou une page web publique.

4. Étape 2 : envoyer un document

Toutes les méthodes visent le même point d’entrée, celui du projet.

MéthodeFormatQuand l’utiliser
A — Envoi direct de fichiermultipart/form-dataFichiers générés localement ou stockés sur votre serveur
B — URL distante ou présignéeJSONFichiers déjà sur AWS S3, Google Cloud Storage, Azure Blob ou générés par votre ERP
C — Base64JSONApplications mobiles, numériseurs connectés, fonctions serverless sans système de fichiers
D — Courriel entrant (sans code)CourrielChaque projet a son adresse de capture et sa liste d’expéditeurs approuvés (onglet « Réception »)

L’API accepte aussi un fichier unique envoyé en flux binaire brut dans le corps de la requête.

Quotas et règles

RègleValeur
Formats acceptésPDF, PNG, JPEG, WEBP, TIFF, HEIC (HEIF)
Taille maximale par fichier25 Mo (après décodage pour le base64)
Documents par requête25 au maximum

Pour les gros volumes, envoyez plusieurs requêtes, ou passez par des URL présignées (méthode B) plutôt que par le base64.

Paramètres communs. autoProcess lance l’extraction dès la réception ; il est activé par défaut, false le désactive. metadata.externalId conserve votre référence métier : elle vous est renvoyée telle quelle dans la réponse et à l’export.

Méthode A — Envoi direct de fichier (multipart/form-data)

curl -X POST "https://<workspace>.docs.scanee.ai/<projet>/ingest" \
  -H "X-API-Key: scanee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -F "files=@./facture_01.pdf" \
  -F 'metadata={"externalId": "ERP-INV-1092", "departement": "Comptabilite"}' \
  -F "autoProcess=true"
ChampRôle
filesLe ou les fichiers du lot. Répétez le champ pour envoyer plusieurs documents dans le même appel, jusqu’à 25
metadataObjet JSON libre. externalId porte votre référence métier
autoProcessActivé par défaut ; false dépose le document sans lancer l’extraction

Au-delà de 25 fichiers, la requête est rejetée en 400 BATCH_LIMIT_EXCEEDED : scindez en lots de 25.

Node.js / TypeScript (Axios et form-data ; le fichier est lu en flux, sans être chargé entièrement en mémoire) :

import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';

async function sendInvoice() {
  const form = new FormData();
  form.append('files', fs.createReadStream('./facture_01.pdf'));
  form.append('metadata', JSON.stringify({ externalId: 'INV-1092' }));
  form.append('autoProcess', 'true');

  const res = await axios.post(
    'https://<workspace>.docs.scanee.ai/<projet>/ingest',
    form,
    {
      headers: {
        ...form.getHeaders(),
        'X-API-Key': process.env.SCANEE_API_KEY,
      },
    }
  );

  console.log('Document reçu par Scanee :', res.data);
}

Python (Requests) :

import json
import os
import requests

url = "https://<workspace>.docs.scanee.ai/<projet>/ingest"
headers = {"X-API-Key": os.environ["SCANEE_API_KEY"]}

with open("facture_01.pdf", "rb") as f:
    files = [("files", ("facture_01.pdf", f, "application/pdf"))]
    data = {
        "metadata": json.dumps({"externalId": "INV-1092"}),
        "autoProcess": "true",
    }
    res = requests.post(url, headers=headers, files=files, data=data)

print(res.status_code, res.json())

Méthode B — URL distante ou présignée (JSON)

curl -X POST "https://<workspace>.docs.scanee.ai/<projet>/ingest" \
  -H "X-API-Key: scanee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "autoProcess": true,
    "documents": [
      {
        "url": "https://mon-bucket.s3.ca-central-1.amazonaws.com/factures/inv_1092.pdf?X-Amz-Signature=...",
        "filename": "inv_1092.pdf",
        "externalId": "INV-1092"
      }
    ]
  }'

Ce que fait Scanee à la réception :

  1. Téléchargement serveur à serveur. Scanee fait un GET sur l’URL fournie, avec un délai maximal de 30 secondes et un plafond de 25 Mo.
  2. Contrôle du type réel. Scanee ne se fie pas seulement à l’extension ou au type annoncé : il lit les premiers octets du fichier (signature %PDF pour un PDF, en-têtes d’image) pour confirmer le format.
  3. Copie dans l’espace du projet. Le fichier est enregistré, chiffré, dans l’espace isolé du projet.
  4. Réponse 202 Accepted avec le lot et les tâches créées.

Si l’URL ne répond pas, ou renvoie une erreur, la requête est rejetée en 422.

Avantage sécurité. Vous n’ouvrez ni votre réseau ni un accès SFTP. Une URL présignée de 5 ou 10 minutes suffit : une fois le 202 Accepted reçu, Scanee a sa copie de travail et l’URL peut expirer.

Méthode C — Base64 (JSON)

curl -X POST "https://<workspace>.docs.scanee.ai/<projet>/ingest" \
  -H "X-API-Key: scanee_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "autoProcess": true,
    "documents": [
      {
        "filename": "recu_caisse.jpg",
        "data": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
        "externalId": "REC-8801"
      }
    ]
  }'

Le champ data est une URL de données complète, préfixe MIME inclus (data:image/jpeg;base64,), suivie de la charge encodée. Le champ base64 accepte aussi la charge seule. Mêmes limites : 25 Mo par fichier après décodage, 6 formats, 25 documents par requête.

La réponse immédiate : 202 Accepted

Quelle que soit la méthode, la réponse a la même forme :

{
  "status": "success",
  "batchId": "batch_9a4f21de88b0",
  "project": "factures",
  "tenantId": "acme",
  "totalFiles": 1,
  "tasks": [
    {
      "taskId": "1024",
      "filename": "facture_01.pdf",
      "status": "pending",
      "trackingUrl": "https://app.scanee.ai/projects/factures/tasks/67d8f1e2700bd45d79cc1918",
      "externalId": "INV-1092"
    }
  ]
}
  • taskId : numéro séquentiel court attribué au document dans votre projet.
  • trackingUrl : lien direct vers le document dans l’interface Scanee.
  • externalId : votre référence métier, renvoyée telle quelle.

5. Étape 3 : configurer les champs à extraire

Vous ne codez pas de règles d’OCR ni de modèles. Vous définissez les champs voulus dans l’onglet « Champs » du projet.

Type de champUsageExemple de valeur extraite
Input / TextAreaTexte simple ou multiligne"INV-2026-089", "Fournitures ACME inc."
NumberMontant ou quantité1437.50 (séparateurs normalisés)
DatePickerDate2026-09-22T00:00:00.000Z (ISO)
Select / RadioChoix dans une listeDevise : CAD, USD, EUR
List (référentiel)L’IA rapproche le texte de votre liste officielle (fournisseurs, comptes)"Hydro-Qc" → "Hydro-Québec"
Table (multipages)Chaque ligne d’article : description, quantité, prix, total[{"desc": "Article A", "qty": 2, "price": 50}]
Tags (zones 2D)Coordonnées de la donnée sur le document[ymin, xmin, ymax, xmax] normalisés

Consigne IA du projet. Dans l’onglet « Général » du projet, ajoutez une consigne métier en langage naturel. Par exemple : « Pour les factures avec taxes canadiennes, isoler la TPS (5 %) et la TVQ (9,975 %). Si le numéro de bon de commande figure dans les notes, l’extraire dans po_number. »

6. Étape 4 : recevoir les données extraites (webhooks)

Dès qu’un document atteint le statut choisi, Scanee le pousse sur votre serveur par une requête HTTP POST.

Configurer le webhook

  1. Ouvrez l’onglet « Exports » du projet.
  2. Cliquez sur « + Ajouter une configuration » et choisissez le format « API / Zapier / Make » (webhook).
  3. Renseignez le nom (par exemple Webhook ERP Production), l’URL (par exemple https://api.votre-domaine.com/webhooks/scanee) et l’authentification.
AuthentificationEffet
AucunePas d’en-tête d’authentification
BearerAjoute Authorization: Bearer <jeton>
Clé d’APIAjoute un en-tête personnalisé, par défaut x-api-key, ou le nom de votre choix (par exemple X-Webhook-Secret)

Le déclenchement automatique

StatutQuand
Nouveau (new)Dès que le document entre dans le projet, avant l’extraction
En révision (reviewing)L’IA a extrait les données ; le document est prêt à valider. Pour une automatisation complète, sans intervention
Terminé (completed)Une personne a vérifié le document et l’a passé à Terminé : c’est la validation

Vous pouvez aussi déclencher l’envoi à la main, document par document.

La correspondance des champs

Dans l’éditeur d’export, vous associez chaque champ de Scanee à la clé JSON que votre API attend.

Champ source dans ScaneeClé JSON cible (exemple)Rôle
IDscanee_doc_idNuméro séquentiel court (par exemple 1024)
metadata.externalIdexternal_idVotre référence d’origine
details.<id_fournisseur>vendor_nameNom du fournisseur extrait
details.<id_montant_total>total_amountMontant total
details.<id_lignes>itemsLignes d’articles, en tableau d’objets ; table.<id_lignes>.<colonne> donne seulement les valeurs d’une colonne
fileData.signedUrldocument_download_urlLien signé pour télécharger le PDF original
fileData.annotatedSignedUrlannotated_pdf_urlLien du PDF avec les zones de détection

Les clés de sortie sont libres : chaque projet définit son propre schéma. Le même document peut alimenter un ERP avec un schéma, et un logiciel de paie avec un autre, sans transformation de votre côté.

Ce que votre webhook reçoit

Le corps est un tableau JSON, un objet par document :

[
  {
    "scanee_doc_id": 1024,
    "external_id": "INV-1092",
    "invoice_number": "FA-2026-0042",
    "invoice_date": "2026-09-22",
    "vendor_name": "Fournitures ACME inc.",
    "subtotal": 1250.00,
    "gst": 62.50,
    "qst": 124.69,
    "total_amount": 1437.19,
    "currency": "CAD",
    "items": [
      {
        "description": "Licences logicielles annuelles",
        "quantity": 5,
        "unit_price": 200.00,
        "line_total": 1000.00
      },
      {
        "description": "Frais d'installation",
        "quantity": 1,
        "unit_price": 250.00,
        "line_total": 250.00
      }
    ],
    "document_download_url": "https://storage.scanee.ai/storage/export/...?sig=...",
    "annotated_pdf_url": "https://storage.scanee.ai/storage/export-annotated/665f1c...?sig=..."
  }
]

Les liens de téléchargement. document_download_url et annotated_pdf_url sont signés par Scanee (signature HMAC) : votre serveur ou votre ERP peut faire un GET dessus sans s’authentifier à nouveau. Ils ne sont pas devinables, mais ils n’expirent pas : traitez-les comme des données confidentielles et ne les exposez pas publiquement.

Récepteur Node.js / Express

const express = require('express');
const app = express();
app.use(express.json());

app.post('/webhooks/scanee', (req, res) => {
  // 1. Vérifier le secret (authentification « Clé d'API » avec l'en-tête X-Webhook-Secret)
  const webhookSecret = req.headers['x-webhook-secret'];
  if (webhookSecret !== process.env.SCANEE_WEBHOOK_SECRET) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  // 2. Traiter les documents reçus
  for (const doc of req.body) {
    console.log(`Facture reçue : ${doc.invoice_number}, total : ${doc.total_amount}`);
    // Insérer dans votre ERP ou votre base de données
  }

  // 3. Répondre 200 rapidement (moins de 15 secondes)
  res.status(200).json({ status: 'received' });
});

app.listen(3000, () => console.log('Récepteur de webhooks prêt sur le port 3000'));

Récepteur Python / FastAPI

import os
from typing import Any, Dict, List

from fastapi import FastAPI, Header, HTTPException, status

app = FastAPI()
SECRET_TOKEN = os.environ["SCANEE_WEBHOOK_TOKEN"]

@app.post("/webhooks/scanee")
async def receive_scanee_webhook(
    payload: List[Dict[str, Any]],
    authorization: str | None = Header(default=None),
):
    # 1. Vérifier le jeton Bearer
    if authorization != f"Bearer {SECRET_TOKEN}":
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")

    # 2. Traiter les données
    for doc in payload:
        print(f"Document {doc.get('scanee_doc_id')} - montant : {doc.get('total_amount')}")
        # Enregistrer dans votre système

    return {"status": "ok"}

Zapier, Make ou n8n, sans écrire de code

  1. Créez un déclencheur Webhooks by Zapier (ou Custom Webhook dans Make ou n8n).
  2. Copiez l’URL fournie.
  3. Collez-la dans le champ URL du webhook de l’onglet Exports de Scanee.
  4. Envoyez un document de test : les variables mappées apparaissent, prêtes à partir vers Google Sheets, Slack, Airtable, Notion ou votre ERP.

7. Étape 5 : fiabilité, journal et erreurs

Codes HTTP de l’API d’ingestion

CodeCauseAction
202Documents acceptés et mis en fileConserver le taskId ou le batchId
400Requête vide, document sans url ni data, ou plus de 25 documents (BATCH_LIMIT_EXCEEDED)Scinder en lots de 25, vérifier le corps
401Clé absente (MISSING_API_KEY) ou invalide, révoquée (INVALID_API_KEY)Vérifier l’en-tête X-API-Key ou Authorization
403Clé d’un autre espace (KEY_TENANT_MISMATCH) ou non autorisée sur ce projet (KEY_PROJECT_MISMATCH)Vérifier le workspace et le sigle du projet dans l’URL
404Espace de travail ou projet introuvableVérifier l’URL du projet dans l’onglet « Réception »
413Fichier de plus de 25 MoRéduire la résolution ou scinder le document
415Format non acceptéFournir un PDF, PNG, JPEG, WEBP, TIFF ou HEIC
422URL distante inaccessible (méthode B)Vérifier que l’URL est valide et pas encore expirée

Si votre serveur webhook ne répond pas

  1. Nouvelles tentatives automatiques. Si votre serveur répond par une erreur 5xx, ne répond pas dans les 15 secondes ou est injoignable, Scanee garde le message et réessaie automatiquement, jusqu’à 5 tentatives au total.
  2. Pas de nouvelle tentative sur une erreur 4xx. Une réponse 4xx (par exemple 401 ou 404) est considérée comme définitive : corrigez la configuration, puis renvoyez à la main.
  3. Journal complet. Chaque envoi est enregistré dans l’historique du projet : date et heure, code HTTP de réponse, contenu envoyé et message d’erreur.
  4. Renvoi manuel. Si votre serveur était arrêté pendant une maintenance, ouvrez l’historique des webhooks dans Scanee et renvoyez la charge utile.

Votre récepteur doit donc répondre 200 vite, idéalement avant de faire le traitement lourd, et savoir recevoir deux fois le même document : dédoublonnez sur scanee_doc_id ou external_id.

8. Le cycle de vie des fichiers

Quand Scanee reçoit votre document, il en garde une copie de travail chiffrée, isolée dans le projet, pour l’extraction. Vous décidez de ce qu’elle devient.

Suppression automatique

La suppression automatique est désactivée par défaut : les documents restent dans le projet jusqu’à ce que vous les supprimiez. Dans l’onglet « Stockage » du projet, section « Rétention et confidentialité des données », vous pouvez l’activer et fixer une période en jours (7 par défaut ; par exemple 30 ou 90), avec l’un de ces deux modes :

ModeEffet
Supprimer uniquement les fichiersLe PDF est détruit ; les métadonnées et les données extraites restent consultables
Tout purgerLe fichier, les données extraites et l’historique du document sont supprimés

Votre propre stockage (BYOS)

Vous pouvez brancher votre propre stockage : un dossier Google Drive, Microsoft OneDrive, SharePoint ou Dropbox, ou, au forfait Scale, AWS S3, Google Cloud Storage, Azure Blob Storage ou un SFTP d’entreprise.

#ÉtapeDétail
1ExtractionLe traitement du document est terminé
2Délai avant transfertExprimé en heures (24 par défaut), et peut être fixé à 0
3Cycle de transfertLes transferts partent par cycles horaires, ce qui laisse le temps de les annuler
4TransfertLe document part vers votre compartiment ou votre dossier, puis la copie de travail interne est supprimée

À retenir. Le document finit sa vie chez vous sans disparaître de Scanee : une fois transféré, il reste visible dans le projet, qui conserve le lien vers le fichier. Les connexions suivent le protocole du fournisseur : OAuth, compte de service ou clé privée.

9. Aide-mémoire

Envoyer un document :

curl -X POST "https://<workspace>.docs.scanee.ai/<projet>/ingest" \
  -H "X-API-Key: scanee_..." \
  -F "files=@mon_document.pdf" \
  -F 'metadata={"externalId": "REF-001"}'

En-têtes d’authentification acceptés : X-API-Key: scanee_... ou Authorization: Bearer scanee_...

Formats et limites : PDF, PNG, JPEG, WEBP, TIFF, HEIC. 25 Mo par fichier, 25 documents par requête.

Statuts de déclenchement des webhooks :

ValeurStatutQuand
newNouveauDès la réception du document
reviewingEn révisionPrêt à valider, pour l’automatisation complète
completedTerminéAprès la vérification par une personne

Conclusion : une boucle, trois appels, aucune saisie

Vous envoyez un document à l’adresse du projet. Scanee l’extrait selon les champs que vous avez définis. Votre serveur reçoit le JSON et les liens signés du fichier. Le reste (nouvelles tentatives, journal, isolation des projets) est pris en charge par la plateforme.

Prochaine étape. Ouvrez l’onglet « Réception » de votre projet, créez une clé ERP-Prod et envoyez un premier document de test avec la commande de l’aide-mémoire. Le webhook se branche ensuite dans l’onglet « Exports ».

Essayez avec vos propres factures

Essai gratuit de 14 jours, sans carte de crédit.

Essayer gratuitement →