Anonymisation et pseudonymisation par appel HTTP, à intégrer dans vos workflows automatisés (n8n, Make, Zapier, scripts Python ou Node). Hébergé en France, sans cloud tiers, sans LLM.
L'API MasqID expose 3 endpoints webhook pour l'anonymisation et 1 endpoint statique pour récupérer les résultats. Deux flows :
POST /webhook/anonymize) — upload → traitement automatique → polling./anonymize-scan puis /anonymize-apply) — deux étapes, avec validation manuelle des PII entre les deux.Base URL : https://n8n.fsiavocat.com
Base URL statique (résultats) : https://anonymize.fsiavocat.com/status/
L'API est actuellement publique (pas de clé requise) pendant la phase de validation 2026. Une authentification par clé sera ajoutée à la mise en commercialisation. Contact : contact@fsi-avocats.fr
Protection au niveau Nginx (anti-flood, anti-bruteforce) :
/webhook/* (burst 5, zone partagée 10 Mo)/status/* (polling autorisé)HTTP 429 Too Many Requests avec Retry-AfterFiltres applicatifs côté webhook :
" ` $ < > | * ?), leading dotsHTTP 413 Payload Too Large)
Chaque scan génère un jobId au format UUID v4 cryptographique (128 bits d'entropie, CSPRNG via crypto.randomUUID()),
encodé en 32 hex sans tirets. Aucune information temporelle ni séquentielle n'est récupérable depuis le jobId.
// Exemple de jobId valide
"24d0b6bde16145feb8ec481718d4d16a"
// Validation regex backend
/^[a-f0-9]{32}$/
Anonymise un document en une seule étape (scan + application).
Retourne immédiatement un jobId — le traitement est asynchrone.
| Champ | Type | Description |
|---|---|---|
file | binary | Document à traiter (PDF, DOCX, XLSX, MD, TXT) |
mode | string | pseudo (réversible) ou redact (irréversible) |
level | string | maximum (défaut) — niveau de détection |
extra_terms | string (opt) | Termes supplémentaires à détecter, un par ligne |
whitelist_terms | string (opt) | Termes à ignorer, un par ligne |
{
"status": "accepted",
"jobId": "a1b2c3d4e5f6...",
"message": "Document en cours de traitement."
}
Étape 1/2 du workflow review. Lance le scan PII seul et retourne la liste des entités détectées. Le document source est conservé 30 min pour l'étape d'application.
| Champ | Type | Description |
|---|---|---|
file | binary | Document à scanner |
{
"jobId": "a1b2c3d4...",
"fileName": "contrat.pdf",
"fileSizeMB": "0.12",
"pii": {
"terms": [
{ "text": "Jean DUPONT", "type": "REGEX_IDENTITE" },
{ "text": "MonSaaS SAS", "type": "REGEX_SOCIETE" }
],
"summary": { "total_pii": 23 }
},
"status": "scan_completed"
}
Étape 2/2 du workflow review. Applique le traitement sur le document avec la liste de PII filtrée par l'utilisateur.
{
"jobId": "a1b2c3d4...",
"mode": "pseudo",
"fileName": "contrat.pdf",
"pii": [
{ "text": "Jean DUPONT", "type": "PII" },
{ "text": "MonSaaS SAS", "type": "PII" }
]
}
{ "status": "accepted", "jobId": "a1b2c3d4..." }
Polling du statut d'un job. Intervalle recommandé : 4 secondes.
{
"status": "processing",
"pct": 75,
"message": "Génération du document anonymisé...",
"mode": "pseudo",
"fileName": "contrat.pdf"
}
{
"status": "completed",
"pct": 100,
"mode": "pseudo",
"fileName": "contrat.pdf",
"entityCount": 23,
"wordCount": 2145,
"hasMapping": true,
"hasPreview": true,
"hasDoc": true,
"docExt": "pdf",
"hasSignature": false,
"hasEncrypted": false,
"completedTime": "2026-04-20T14:32:18Z"
}
completed)/status/{jobId}_doc.{ext} — document anonymisé (PDF/DOCX/XLSX/EML/MBOX/MSG/MD/TXT au format d'origine)/status/{jobId}_preview.md — aperçu Markdown du document anonymisé/status/{jobId}_source.md — texte source extrait (pour validation side-by-side)/status/{jobId}_mapping.json — table de correspondance (mode pseudo)/status/{jobId}_pii.json — entités détectées + métadonnées (catégorie, rôle, sources de validation)Les artefacts suivants sont produits dans votre navigateur à partir des fichiers ci-dessus (aucun endpoint serveur, aucune exposition de données originales) :
original;pseudonyme;type;role;occurrences (séparateur ;, BOM UTF-8 Excel-compatible)..enc.json) — chiffrement de niveau bancaire (AES-256-GCM) avec mot de passe utilisateur. Déchiffrement local via /depseudo.html.Exécution entièrement automatique. Pas d'intervention humaine.
# 1. Upload
curl -X POST https://n8n.fsiavocat.com/webhook/anonymize \
-F "file=@contrat.pdf" \
-F "mode=pseudo" \
-F "level=maximum"
# Response : { "jobId": "a1b2c3d4...", "status": "accepted" }
# 2. Polling
JOB_ID="a1b2c3d4..."
while true; do
STATUS=$(curl -s "https://anonymize.fsiavocat.com/status/${JOB_ID}.json")
STATE=$(echo "$STATUS" | jq -r .status)
echo "$STATE"
[ "$STATE" = "completed" ] && break
sleep 4
done
# 3. Téléchargement
curl -O "https://anonymize.fsiavocat.com/status/${JOB_ID}_doc.pdf"
curl -O "https://anonymize.fsiavocat.com/status/${JOB_ID}_mapping.json"
Valider manuellement la liste des PII avant le traitement. Idéal pour les documents complexes où les faux positifs doivent être écartés.
# 1. Scan
curl -X POST https://n8n.fsiavocat.com/webhook/anonymize-scan \
-F "file=@contrat.pdf"
# Response : { "jobId": "...", "pii": { "terms": [...] } }
# 2. Filtrer les PII côté client (exemple : retirer les faux positifs,
# ajouter des termes manuels) ... traitement custom
# 3. Apply avec la liste filtrée
curl -X POST https://n8n.fsiavocat.com/webhook/anonymize-apply \
-H "Content-Type: application/json" \
-d '{
"jobId": "a1b2c3d4...",
"mode": "pseudo",
"fileName": "contrat.pdf",
"pii": [
{ "text": "Jean DUPONT", "type": "PII" },
{ "text": "MonSaaS SAS", "type": "PII" }
]
}'
# 4. Polling + téléchargement (idem workflow simple)
Aucun endpoint serveur n'est exposé pour la dépseudonymisation : la restauration s'effectue
100 % côté navigateur via /depseudo.html
(interface drag & drop) ou directement en local en croisant mapping.json avec le document
pseudonymisé.
Logique de restauration (pseudo-code) :
// 1. Charger mapping.json (clair ou .enc.json déchiffré localement)
const mapping = JSON.parse(text);
// 2. Pour chaque placeholder dans le document, remplacer par sa version canonique
for (const [placeholder, info] of Object.entries(mapping.reverse)) {
text = text.replaceAll(`<${placeholder.replace(/^<|>$/g, '')}>`, info.canonical);
}
// 3. Le mapping reverse contient également les variantes capturées
// (ex: "DUPONT" / "M. DUPONT" / "Jean DUPONT") — utile pour les
// documents partiellement pseudonymisés.
| Code | Signification | Causes typiques |
|---|---|---|
200 | OK | Scan terminé (endpoint scan only) |
202 | Accepted | Job créé, traitement asynchrone |
400 | Bad Request | Paramètres invalides, mode inconnu, jobId mal formé |
413 | Payload Too Large | Fichier > 256 Mo |
429 | Too Many Requests | Rate limit dépassé |
500 | Server Error | Erreur du pipeline (scan, extraction, format non supporté) |
const fs = require('fs');
const FormData = require('form-data');
const fetch = require('node-fetch');
async function anonymize(filePath, mode = 'pseudo') {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
form.append('mode', mode);
form.append('level', 'maximum');
const res = await fetch('https://n8n.fsiavocat.com/webhook/anonymize', {
method: 'POST',
body: form
});
const { jobId } = await res.json();
while (true) {
const r = await fetch(`https://anonymize.fsiavocat.com/status/${jobId}.json`);
const data = await r.json();
if (data.status === 'completed') return data;
await new Promise(rs => setTimeout(rs, 4000));
}
}
import time
import requests
def anonymize(file_path, mode='pseudo'):
with open(file_path, 'rb') as f:
r = requests.post(
'https://n8n.fsiavocat.com/webhook/anonymize',
files={'file': f},
data={'mode': mode, 'level': 'maximum'},
)
job_id = r.json()['jobId']
while True:
status = requests.get(
f'https://anonymize.fsiavocat.com/status/{job_id}.json'
).json()
if status['status'] == 'completed':
return job_id, status
time.sleep(4)
Utilisez un nœud HTTP Request avec POST, Content-Type
multipart/form-data, et les champs file (binary) + mode.
Le polling peut se faire avec un nœud Wait + HTTP Request en boucle.
L'API est ouverte. Testez sur 1 document, puis scalez.