🔧 Référence API — Edge Functions v2
Base URL & Authentification
Base URL : https://<SUPABASE_PROJECT_ID>.supabase.co/functions/v1/
Header requis :
Authorization: Bearer <SUPABASE_ANON_KEY>
Content-Type: application/json
ℹ️
verify_jwt = falseen configuration actuelle (MVP). Migration vers JWT obligatoire prévue Q2 2026.
1. analyze-email-headers
Méthode : POST
Réponse : Server-Sent Events (SSE streaming)
Content-Type réponse : text/event-stream
Requête
{
"emailHeaders": "Delivered-To: user@gmail.com\nReceived: from...\n...",
"enabledApis": {
"ipQualityScore": true,
"abuseIPDB": false,
"virusTotal": false
},
"apiKeys": {
"ipQualityScore": "YOUR_KEY",
"abuseIPDB": "",
"virusTotal": ""
}
}
Events SSE émis
Format de chaque event : data: <JSON>\n\n
interface AnalysisStep {
step: string;
status: 'processing' | 'success' | 'warning' | 'error';
data: { message: string; [key: string]: any };
progress: number; // 0-100
}
| Step | Progress | Données clés |
|---|---|---|
basic_parsing | 10% | from, subject, date, domains, ipv4 |
ip_parsing | 20% | ipv4[], ipv6[] |
received_chain | 30% | chain[], tls, cipher |
domain_arc | 40% | domain, arcSeal, arcAuth |
ip_reputation | 55% | reputations[] (IPQS, AbuseIPDB, VirusTotal) |
spf | 73% | status: pass/fail/neutral |
dkim | 85% | status: pass/fail/neutral |
complete | 100% | summary complet |
Suivi de data: [DONE] pour fin du stream.
Consommation depuis le frontend
const response = await fetch(
`${import.meta.env.VITE_SUPABASE_URL}/functions/v1/analyze-email-headers`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY}`,
},
body: JSON.stringify({ emailHeaders, enabledApis, apiKeys })
}
);
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ') && !line.includes('[DONE]')) {
const step = JSON.parse(line.slice(6));
// traiter step...
}
}
}
2. analyze-spam
Méthode : POST
Réponse : JSON synchrone
Requête
{
"emailContent": "Contenu de l'email...",
"subject": "Votre colis est prêt",
"from": "dpd@thepiratebuy.com",
"headers": "Received: from...",
"spf": "fail",
"dkim": "pass",
"dmarc": "fail",
"ipBlacklisted": false,
"rdnsMismatch": false
}
| Champ | Type | Obligatoire |
|---|---|---|
emailContent | string | ✅ (ou headers) |
subject | string | Non (extrait de headers si absent) |
from | string | Non |
headers | string | Non |
spf | string | Non (pass/fail/neutral) |
dkim | string | Non |
dmarc | string | Non |
ipBlacklisted | boolean | Non (défaut: false) |
rdnsMismatch | boolean | Non (défaut: false) |
Réponse
{
"score": 78,
"patternScore": 85,
"headerScore": 45,
"threatLevel": "dangerous",
"severity": "high",
"is_spam": true,
"matchedPatterns": [
{
"patternId": "PHISH-001",
"type": "phishing",
"score": 72,
"severity": "high",
"reasons": [
"Mots-clés: colis, livraison",
"Domaine suspect: thepiratebuy.com"
],
"matchScore": 85
}
],
"headerFindings": [
{ "ruleId": "HDR-001", "check": "spf", "modifier": 25 },
{ "ruleId": "HDR-003", "check": "dmarc", "modifier": 20 }
],
"totalPatternsChecked": 13,
"totalRulesChecked": 5,
"summary": {
"patternsMatched": 1,
"topReasons": ["Mots-clés: colis, livraison", "Domaine suspect"],
"categories": ["phishing"]
},
"analyzedAt": "2026-04-19T10:00:00.000Z"
}
3. arcep-check
Méthode : POST
Réponse : JSON synchrone
Actions : check | info | refresh
Requête — check
{ "action": "check", "phoneNumber": "0612345678" }
Formats acceptés : 0612345678, +33612345678, 0033612345678, 06 12 34 56 78, 06-12-34-56-78
Réponse — check
{
"phoneNumber": "0612345678",
"normalized": "33612345678",
"isBlocked": true,
"matchCount": 2,
"matches": [
{ "name": "Démarchage commercial", "action": "block", "pattern": "336123#####" }
],
"database": {
"version": "v2026.02.26.17.26",
"total_blocked": 14000000
}
}
Requête — info
{ "action": "info" }
Réponse : version, description, nombre de patterns, date cache.
Requête — refresh
{ "action": "refresh" }
Force le rechargement de la base depuis Codeberg (ignore le cache 1h).
4. trigger-n8n-export
Méthode : POST
Réponse : JSON synchrone
Requête
{
"analysisData": {
"spf": "fail",
"dkim": "pass",
"dmarc": "fail",
"threatLevel": "high",
"from": "attacker@evil.com"
},
"n8nWebhookUrl": "https://your-n8n.com/webhook/abc123",
"exports": { "sheets": true, "xml": true, "json": true, "calendar": true }
}
Payload envoyé au webhook n8n
{
"timestamp": "2026-04-19T10:00:00.000Z",
"analysis": { "spf": "fail", ... },
"exports": { "sheets": true, ... },
"formats": {
"json": "{\"spf\":\"fail\",...}",
"xml": "<?xml version=\"1.0\"...>",
"csv": "spf,dkim,...\nfail,pass,...",
"calendar": "BEGIN:VCALENDAR\n..."
}
}
5. trigger-make-scenario
Méthode : POST
Réponse : JSON synchrone
Requête
{
"action": "analyze_spam",
"emailHeaders": "Received: from...",
"analysisData": { "spf": "fail", "threatLevel": "high" },
"customWebhookUrl": "https://hook.eu2.make.com/abc123"
}
Si customWebhookUrl et le secret MAKE_WEBHOOK_URL sont absents → erreur 400.
Système de crédits
- 5 analyses/jour (reset automatique à minuit UTC)
- Applicable aux endpoints
analyze-email-headersetarcep-check - Géré côté client via
localStorage(MVP) → migration vers DB en Q2 2026
Codes d'erreur communs
| Code HTTP | Signification | Exemple |
|---|---|---|
| 400 | Données manquantes ou invalides | emailHeaders absent |
| 401 | Non authentifié (si verify_jwt activé) | Token expiré |
| 429 | Quota de crédits dépassé | 5 analyses/jour atteint |
| 500 | Erreur serveur ou service tiers indisponible | ARCEP unreachable |
API REST v1 publique (Q2 2026)
L'API REST v1 sera disponible en Q2 2026 avec :
- Authentification Bearer token dédié (distinct de la clé Supabase)
- Rate limiting : 100 req/min, 10 000/jour
- Documentation OpenAPI 3.0 + Swagger UI
- Plans : Free / Pro / Enterprise avec quotas différenciés
Endpoints prévus :
POST /api/v1/email/analyze
POST /api/v1/phone/check
GET /api/v1/account/usage
GET /api/v1/account/credits
Voir ROADMAP.md pour le calendrier complet.