Aller au contenu principal

Limites de débit (Rate Limits)

Pour garantir une qualité de service optimale à tous les utilisateurs, l'API Infoparcelle applique des limites de débit sur les requêtes.

Limites globales

Limite actuelle

  • 1200 requêtes par minute (soit 20 requêtes par seconde)
  • Le compteur se réinitialise automatiquement chaque minute
  • S'applique à toutes les requêtes authentifiées avec la même clé API

Quotas mensuels

Les quotas dépendent de votre plan d'abonnement :

PlanCrédits/moisAppels standardsPrix
🌱 Starter5 000~50025€/mois
🚀 Business25 000~2 500100€/mois
💼 Pro50 000~5 000200€/mois
🏢 Enterprise250 000~25 000750€/mois
🌟 Scale500 000~50 0001 250€/mois
🚀 Enterprise+1 000 000+~100 000+Sur mesure
Dépassement de quota

Lorsque vous atteignez votre quota mensuel, vous pouvez soit :

  • Activer les dépassements : paiement à l'usage au-delà du quota
  • Passer à un plan supérieur : augmenter votre quota mensuel

Erreur 429 - Trop de requêtes

Quand se produit cette erreur ?

Vous recevez une erreur 429 Too Many Requests lorsque vous dépassez la limite de 1200 requêtes par minute (soit 20 requêtes par seconde).

Réponse type

HTTP/1.1 429 Too Many Requests
Retry-After: 30
{
"error": "rate_limit_exceeded",
"message": "Limite de débit dépassée. Maximum 20 requêtes par seconde.",
"retry_after": 30
}

Le header Retry-After indique le nombre de secondes à attendre avant de réessayer.

Bonnes pratiques

1. Implémenter un système de retry

async function fetchWithRetry(url, options = {}, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${apiKey}`,
...options.headers,
},
});

// Si on atteint la limite
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limit atteinte. Attente de ${retryAfter}s...`);

// Attendre avant de réessayer
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}

// Si la requête réussit
if (response.ok) {
return await response.json();
}

// Autres erreurs
throw new Error(`HTTP ${response.status}: ${await response.text()}`);

} catch (error) {
if (i === maxRetries - 1) throw error;

// Backoff exponentiel
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}

// Utilisation
const data = await fetchWithRetry(
'https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=1+Rue+de+Rivoli'
);

2. Espacer vos requêtes

Pour rester sous la limite de 20 requêtes/seconde, espacez vos requêtes :

class RateLimiter {
constructor(maxRequests = 20, interval = 1000) {
this.maxRequests = maxRequests;
this.interval = interval;
this.queue = [];
this.processing = false;
}

async execute(fn) {
return new Promise((resolve, reject) => {
this.queue.push({ fn, resolve, reject });
this.process();
});
}

async process() {
if (this.processing || this.queue.length === 0) return;

this.processing = true;

while (this.queue.length > 0) {
const batch = this.queue.splice(0, this.maxRequests);

await Promise.all(
batch.map(async ({ fn, resolve, reject }) => {
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
})
);

if (this.queue.length > 0) {
await new Promise(resolve => setTimeout(resolve, this.interval));
}
}

this.processing = false;
}
}

// Utilisation
const limiter = new RateLimiter(20, 1000); // 20 requêtes par seconde

const adresses = ['1+Rue+de+Rivoli', 'Place+des', '5+Avenue+de+la', /* ... */];

const results = await Promise.all(
adresses.map(adresse =>
limiter.execute(() =>
fetch(`https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=${adresse}`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
}).then(r => r.json())
)
)
);

3. Mettre en cache les données

Cachez les données qui changent rarement :

class ApiCache {
constructor(ttl = 3600000) { // 1 heure par défaut
this.cache = new Map();
this.ttl = ttl;
}

get(key) {
const item = this.cache.get(key);

if (!item) return null;

if (Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}

return item.value;
}

set(key, value) {
this.cache.set(key, {
value,
expiry: Date.now() + this.ttl,
});
}
}

// Utilisation
const cache = new ApiCache(3600000); // 1 heure

async function fetchWithCache(url) {
const cached = cache.get(url);
if (cached) {
console.log('Résultat depuis le cache');
return cached;
}

const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${apiKey}` },
});

const data = await response.json();
cache.set(url, data);

return data;
}

4. Optimiser les requêtes

Utilisez le paramètre champs

Ne récupérez que les données dont vous avez besoin :

# ❌ Récupère tous les champs (plus lourd)
curl "https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=1+Rue+de+Rivoli"

# ✅ Récupère uniquement les champs nécessaires
curl "https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=1+Rue+de+Rivoli&champs=identifiant_ban,adresse_complete,centre"

Limitez le nombre de résultats

# ❌ Récupère 10 résultats par défaut
curl "https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=1+Rue+de+Rivoli"

# ✅ Récupère uniquement le meilleur résultat
curl "https://app.infoparcelle.fr/api/v1/geocoder/search?recherche=1+Rue+de+Rivoli&limite=1"

Privilégiez les géométries légères

# ❌ Contour complet (lourd)
curl "https://app.infoparcelle.fr/api/v1/parcelles/12345?geometrie=contour"

# ✅ Point central (léger)
curl "https://app.infoparcelle.fr/api/v1/parcelles/12345?geometrie=centre"

5. Surveiller votre utilisation

Consultez régulièrement votre tableau de bord API pour :

  • Voir votre consommation quotidienne/mensuelle
  • Identifier les pics d'utilisation
  • Anticiper les dépassements de quota

Codes d'erreur liés aux limites

CodeMessageSolution
429Trop de requêtesAttendez la période indiquée dans Retry-After
434Quota dépasséActivez les dépassements ou passez à un plan supérieur
435Mise à niveau requisePassez à un plan supérieur pour accéder à cette fonctionnalité

Prochaines étapes