Les workflows n8n échouent lorsque les API d'enrichissement renvoient du JSON incohérent : un prospect a un champ téléphone, le suivant non, un troisième renvoie null au lieu d'une chaîne vide. Ce tutoriel construit un normalisateur d'enrichissement compatible n8n qui interroge l'API Scavio pour le contexte de l'entreprise, puis normalise chaque réponse en un schéma garanti sans champs manquants.
Prérequis
- n8n installé (auto-hébergé ou cloud)
- Une clé API Scavio depuis scavio.dev
- Connaissance de base des nœuds HTTP Request n8n
Parcours
Étape 1: Configurer le nœud HTTP Request pour Scavio
Configurer un nœud HTTP Request n8n pour appeler l'API Scavio pour l'entreprise de chaque prospect.
// n8n HTTP Request Node:
// Method: POST
// URL: https://api.scavio.dev/api/v1/search
// Headers: x-api-key: {{ $env.SCAVIO_API_KEY }}
// Body: { "query": "{{ $json.company_name }} company", "country_code": "us" }
// Python equivalent for testing:
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
def enrich_company(name):
return requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': f'{name} company', 'country_code': 'us'}).json()
print(f"Results: {len(enrich_company('Scavio').get('organic_results', []))}")Étape 2: Normaliser la réponse en un schéma garanti
Utiliser un nœud Function n8n pour transformer les réponses brutes en objets avec des champs garantis.
// n8n Function Node after HTTP Request
const raw = $input.first().json;
const results = raw.organic_results || [];
const top = results[0] || {};
const kg = raw.knowledge_graph || {};
return [{ json: {
company_name: $('Trigger').first().json.company_name || '',
lead_email: $('Trigger').first().json.email || '',
website: top.link || '',
description: top.snippet || '',
serp_title: top.title || '',
kg_description: kg.description || '',
kg_type: kg.type || '',
total_results: results.length,
enriched_at: new Date().toISOString(),
has_data: results.length > 0,
}}];Étape 3: Ajouter un enrichissement de contexte Reddit
Enchaîner une deuxième requête HTTP pour rechercher l'entreprise sur Reddit, en ajoutant un contexte de sentiment.
// Second HTTP Request: POST https://api.scavio.dev/api/v1/search
// Body: { "query": "{{ $json.company_name }} review", "platform": "reddit", "country_code": "us" }
// Reddit Normalizer Function Node:
const raw = $input.first().json;
const results = raw.organic_results || [];
const prev = $('Google Normalizer').first().json;
return [{ json: {
...prev,
reddit_mentions: results.length,
reddit_top_title: results[0]?.title || '',
reddit_top_snippet: results[0]?.snippet || '',
has_reddit_presence: results.length > 0,
}}];Étape 4: Router les prospects par qualité d'enrichissement
Utiliser des nœuds IF pour envoyer les prospects bien enrichis vers le suivi et les faibles vers une révision manuelle.
// n8n IF Node:
// Condition: {{ $json.has_data }} equals true AND {{ $json.total_results }} >= 3
// True -> auto-route to CRM
// False -> manual review queue
// Python routing equivalent:
def route_lead(enriched):
if enriched['has_data'] and enriched['total_results'] >= 3:
return 'high_confidence' if enriched['has_reddit_presence'] else 'medium_confidence'
return 'manual_review'
for lead in [{'company_name': 'Stripe', 'has_data': True, 'total_results': 5, 'has_reddit_presence': True},
{'company_name': 'Unknown', 'has_data': False, 'total_results': 0, 'has_reddit_presence': False}]:
print(f"{lead['company_name']}: {route_lead(lead)}")Exemple Python
import os, requests
API_KEY = os.environ['SCAVIO_API_KEY']
H = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
def enrich(company):
g = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': f'{company} company', 'country_code': 'us'}).json()
r = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': f'{company} review', 'platform': 'reddit', 'country_code': 'us'}).json()
gr = g.get('organic_results', [])
rr = r.get('organic_results', [])
return {'company': company, 'website': gr[0]['link'] if gr else '', 'google': len(gr),
'reddit': len(rr), 'confidence': 'high' if len(gr) >= 3 and rr else 'low'}
for c in ['Stripe', 'Scavio', 'Unknown']:
e = enrich(c)
print(f"{e['company']}: {e['confidence']} ({e['google']}G, {e['reddit']}R)")Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const H = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' };
async function enrich(company) {
const [g, r] = await Promise.all([
fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: H,
body: JSON.stringify({ query: `${company} company`, country_code: 'us' })
}).then(r => r.json()),
fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: H,
body: JSON.stringify({ query: `${company} review`, platform: 'reddit', country_code: 'us' })
}).then(r => r.json()),
]);
const gr = g.organic_results || [];
const rr = r.organic_results || [];
console.log(`${company}: ${gr.length}G, ${rr.length}R`);
}
(async () => { for (const c of ['Stripe', 'Scavio']) await enrich(c); })();Sortie attendue
Stripe: high (5G, 3R)
Scavio: high (4G, 2R)
Unknown: low (0G, 0R)
Cost: $0.030