Référence
Codes d'erreur
Tous les endpoints renvoient les mêmes codes, avec la même forme de corps. Cette page dit quoi faire de chacun.
Référence complète
| Code | Signification | Cause fréquente | Solution |
|---|---|---|---|
400 | Bad Request | Corps JSON illisible, paramètre manquant ou hors limites. | Vérifier le format des paramètres. Le champ error nomme précisément celui qui pose problème. |
401 | Unauthorized | Clé API absente, invalide ou révoquée. | Vérifier l'en-tête Authorization: Bearer sr_live_…. |
402 | Payment Required | Crédits insuffisants : solde nul, ou inférieur au coût de l'action demandée. | Recharger sur subreply.io/billing. |
422 | Unprocessable | Post Reddit verrouillé, archivé, supprimé, ou compte de publication indisponible. | Choisir un post récent et commentable. Retenter à l'identique ne changera rien. |
500 | Internal Server Error | Échec du pipeline IA ou du scraping. | Réessayer dans 30 s ; contacter le support si l'erreur persiste. |
503 | Service Unavailable | Service de publication indisponible ou aucun compte publiable. | Réessayer dans 60 s. |
202 n'est pas une erreur
POST /api/v1/publish peut répondre 202: la demande est partie, la publication n'est pas confirmée, rien n'est débité. Ce n'est pas un échec à retenter — voir publier un commentaire.Format des erreurs
Toute réponse en échec porte un objet JSON à un seul champ, error, en français et lisible par un humain :
Corps d'erreur
{
"error": "Message explicite en français"
}Il n'y a ni code d'erreur interne, ni champ details: le statut HTTP porte la catégorie, le message porte le détail. Ne parsez jamais le texte du message pour décider d'une action — branchez sur le statut.
Gestion des erreurs en production
Trois règles suffisent à tenir un workflow :
- Retenter 500 et 503, avec un délai croissant et deux tentatives au plus. Ce sont les seuls codes qui se résolvent d'eux-mêmes.
- Couper sur 402 et prévenir : tous les appels suivants échoueront pareil tant que le solde n'est pas rechargé.
- Ne jamais retenter 400, 401 et 422 — il y a quelque chose à corriger dans la requête, la clé ou le post visé.
Client avec retry et garde-fou crédits
type ApiError = { error: string };
// Retente uniquement ce qui mérite de l'être : 503 (service de publication
// momentanément indisponible) et 500 (échec du pipeline IA ou du scraping).
// Un 400, un 401 ou un 422 ne s'arrangeront pas tout seuls.
const RETRYABLE = new Set([500, 503]);
async function callSubreply<T>(
endpoint: string,
body: unknown,
attempt = 0,
): Promise<T> {
const response = await fetch(`https://subreply.io/api/v1/${endpoint}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.SUBREPLY_API_KEY}`,
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(180_000),
});
if (response.ok) return (await response.json()) as T;
const { error } = (await response.json()) as ApiError;
// 402 : plus de crédits. Inutile d'insister — on coupe la chaîne et on
// prévient, plutôt que d'enchaîner des appels qui échoueront tous.
if (response.status === 402) {
await notifyOutOfCredits(error);
throw new Error(`Crédits épuisés : ${error}`);
}
if (RETRYABLE.has(response.status) && attempt < 2) {
// 30 s puis 60 s : le temps qu'un service reparte.
await new Promise((resolve) => setTimeout(resolve, 30_000 * (attempt + 1)));
return callSubreply<T>(endpoint, body, attempt + 1);
}
throw new Error(`SubReply ${response.status} : ${error}`);
}Les rejeux ne coûtent rien
La génération et la publication sont facturées de façon idempotente par URL de post : une seconde tentative sur le même post renvoie
credits_used: 0. Un retry après timeout est donc gratuit — sur /publish, vérifiez quand même le post avant de rejouer, pour ne pas y laisser deux commentaires.