Estructura del resultado
El resultado responde a tres preguntas: qué valores se calcularon, qué problemas se encontraron y qué sustitución o cambio puede proponerse para cada aparición.
Una métrica activa siempre se evalúa, pero su salida depende del tipo: las mediciones aparecen una vez; las reglas solo aparecen cuando encuentran ocurrencias.
result.measurements[]Mediciones
Valores numéricos calculados. Cada entrada de result.measurements se identifica por metric_id; value se interpreta junto con unit e implementation_version.
Métricas y reglas →result.recommendations[]Recomendaciones
Problemas agrupados por regla. Cada elemento explica el problema y reúne en occurrences todas sus apariciones concretas en el texto.
Métricas y reglas →Estructura de una recomendación y sus cambios
Una recommendation describe el tipo de problema; cada occurrence indica dónde aparece y si arText dispone de una sustitución o edición concreta.
recommendations[].metric_idIdentificador estable de la regla. Su definición se consulta en GET /v1/metrics.recommendations[].summaryExplicación del problema encontrado en este informe.recommendations[].guidance[]Orientación general para revisar el problema; no equivale necesariamente a una sustitución literal.recommendations[].examplesEjemplos redactados que ilustran la recomendación, en texto plano con saltos de línea significativos. Acompañan a la regla, no citan el texto analizado y no varían de un informe a otro. null cuando la regla no tiene ejemplos.occurrences[].textFragmento detectado por la métrica.occurrences[].start / endRango sobre el texto original medido en puntos de código Unicode; start es inclusivo y end exclusivo.occurrences[].replacementSustitución textual preferida cuando existe. null significa que la regla no ofrece una sustitución directa.occurrences[].alternatives[]Otras sustituciones revisadas, sin repetir replacement. Puede ser un array vacío.occurrences[].edits[]Cambios seguros normalizados como {start, end, text}. text vacío elimina el rango y start igual a end inserta texto.Una ocurrencia sigue siendo un problema válido aunque replacement sea null y edits esté vacío. En ese caso debe mostrarse la explicación y dejar la revisión a la persona usuaria; la integración no debe fabricar un cambio.
Offsets: cómo recortar el fragmento
start y end se refieren al texto EXACTO que enviaste en text: sin normalizar, sin recortar espacios y sin reordenar. El informe no te devuelve ese texto, así que la unidad importa.
offset_unit es unicode_code_points, no unidades UTF-16 ni bytes. Un solo carácter fuera del BMP —un emoji, ciertos ideogramas, algunos símbolos matemáticos— desplaza todos los offsets posteriores en los lenguajes que indexan en UTF-16. Es un fallo que no aparece en las pruebas y sí con documentos reales.
Pythontexto[start:end] — correcto tal cual: las cadenas de Python ya son puntos de código.JavaScript[...texto].slice(start, end).join("") — texto.slice(start, end) NO es correcto. El SDK oficial trae sliceByCodePoints y codePointToUtf16Index.Java · C#texto.codePoints() / StringInfo — las cadenas son UTF-16; hay que convertir antes de indexar.Go[]rune(texto)[start:end] — las cadenas son bytes; conviértelas a runas.Guarda tú el texto analizado, indexado por report_id o por tu external_id: es el único sitio donde los offsets significan algo, y la API no lo conserva más allá de la retención del informe.
200 · Completado
{
"error": null,
"external_id": "document-123",
"position_in_queue": null,
"report_id": "rep_7f12a4c8",
"result": {
"genre": {
"domain": {
"name": "Lenguaje claro",
"slug": "lenguaje-claro"
},
"text_type": {
"name": "Texto jur\u00eddico-administrativo",
"slug": "texto-juridico-administrativo-dirigido-a-la-ciudadania"
}
},
"language": "es",
"measurements": [
{
"implementation_version": "1.0",
"metric_id": "word-count",
"unit": "words",
"value": 12
}
],
"offset_unit": "unicode_code_points",
"recommendations": [
{
"category": "lexical",
"explanation": null,
"guidance": [
"Elimina la expresi\u00f3n si el contexto lo permite."
],
"id": "rec_1",
"implementation_version": "1.0",
"metric_id": "redundant-expressions",
"metric_title": "Eliminaci\u00f3n de expresiones redundantes",
"occurrences": [
{
"alternatives": [],
"edits": [
{
"end": 16,
"start": 0,
"text": ""
}
],
"end": 16,
"id": "occ_1",
"paragraph_index": 0,
"replacement": null,
"sentence_index": 0,
"start": 0,
"text": "En el d\u00eda de hoy"
}
],
"summary": "Conviene formular el fragmento de manera m\u00e1s directa."
}
],
"schema_version": "2.0"
},
"status": "completed"
}