Códigos de error y respuesta
La API de Discuse indica los problemas de dos maneras: mediante un estado de error HTTP con un message, o mediante una respuesta normal 200 cuyos campos te indican qué ha ocurrido. Esta página enumera todos los casos para que puedas gestionarlos correctamente, y explica el punto que suele causar confusión: agotar la cuota de facturación no es un error HTTP.
¿Qué estados HTTP devuelve la API?
| Status | Cuándo | Qué hacer |
|---|---|---|
200 |
Éxito, incluido el caso de "cuota agotada" | Revisa el cuerpo de la respuesta; un 200 no siempre significa que todo esté correcto (ver más abajo) |
400 |
Falló la validación de la solicitud: contenido vacío, text con más de 10.000 caracteres o demasiadas URLs de medios |
Corrige la solicitud; no la reintentes sin cambios |
401 |
Clave de API ausente o no válida | Comprueba el encabezado X-API-Key; no lo reintentes sin cambios |
429 |
Se superó el límite de frecuencia para la clave | Espera y reintenta después de la ventana de un minuto |
500 |
Error interno o de un servicio dependiente | Reintenta con espera progresiva |
Lee el message en cualquier respuesta que no sea 2xx. Los fallos de autenticación devuelven 401, los fallos por límite de frecuencia devuelven 429 y los fallos de validación de la solicitud devuelven 400; trata los 5xx como transitorios y reintenta con espera progresiva.
¿Por qué "cuota agotada" es un 200 y no un error?
Cuando un proyecto consume su asignación mensual de solicitudes de API, POST /api/v2/check sigue devolviendo 200: el contenido se trata como si no tuviera infracciones, se incluye un message que explica que la cuota está agotada y un objeto usage que muestra que no queda saldo:
{
"has_violations": false,
"message": "API quota exceeded. Current: 10000, Limit: 10000",
"usage": {
"api_requests_used": 10000,
"api_requests_limit": 10000,
"api_requests_remaining": 0
}
}
Esto es intencionado: quedarse sin cuota no debería parecer un fallo del servidor ni bloquear tu canalización con una excepción. Comprueba usage.api_requests_remaining (y el message) en lugar de confiar solo en el código de estado. Si permites el paso ante un 200, una cuota agotada dejaría pasar contenido sin revisar de forma silenciosa; por eso debes ramificar explícitamente según estos campos.
¿Cómo debo leer una respuesta correcta?
Un 200 de /api/v2/check siempre incluye has_violations y cached; el resto es opcional:
| Field | Type | Meaning |
|---|---|---|
has_violations |
boolean | Verdadero si alguna comprobación habilitada marcó el contenido |
cached |
boolean | Verdadero si se sirvió desde una caché reciente de una solicitud idéntica |
message |
string | Presente cuando se agota la cuota (y en avisos similares que no son errores) |
request_id |
string | Se devuelve si lo enviaste |
processing_time_ms |
number | Presente cuando la medición de tiempo está habilitada para el proyecto |
usage |
object | api_requests_used, api_requests_limit, api_requests_remaining |
results |
object | Detalle por comprobación (spamfinder, sentiment, images, …) y la marca de nivel superior hits |
Usa has_violations para decidir el veredicto general y, después, revisa results.<check>.hit para saber qué comprobación se activó.
¿Cómo afecta la caché a las respuestas?
Las solicitudes idénticas para el mismo proyecto se deduplican: una repetición devuelve cached: true con el mismo resultado. La caché es por proyecto. Ten en cuenta que una solicitud en caché también cuenta para tu cuota de solicitudes de API: ahorra tiempo de procesamiento, no cuota.
Puedes adjuntar un request_id a una solicitud para tu propia correlación; se devuelve en la respuesta.
Un cliente mínimo y correcto
async function check(content, settings) {
const response = await fetch('https://api.discuse.com/api/v2/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.DISCUSE_API_KEY
},
body: JSON.stringify({ content, settings })
});
// 400: bad request — fix it, don't retry. 5xx: transient/auth/rate-limit — retry with backoff.
if (response.status === 400) {
throw new Error('Invalid request: ' + (await response.text()));
}
if (!response.ok) {
throw new Error(`Discuse error ${response.status}`); // retry upstream with backoff
}
const data = await response.json();
// Quota exhausted is a 200 — never treat it as "checked and clean".
if (data.usage && data.usage.api_requests_remaining === 0 && data.message) {
throw new Error('Quota exhausted: ' + data.message);
}
return data; // inspect data.has_violations and data.results
}
Relacionado
- Autenticación y claves de API — claves, el encabezado
X-API-Keyy límites de frecuencia - Guía de inicio rápido — tu primera solicitud en unos minutos
- Análisis de texto — el objeto
resultsen detalle