AstrApp
Docs

API de datasets

Un dataset es una colección de conversaciones en ChatML lista para entrenar. Con la API creas datasets, importas archivos y lees sus ejemplos.

Rutas

GET/api/v1/datasets
Lista los datasets de tu organización
POST/api/v1/datasets
Crea un dataset con sus ejemplos
POST/api/v1/ingest
Importa un archivo y detecta su formato
POST/api/v1/datasets/upload
Sube un archivo para entrenar
GET/api/v1/datasets/{datasetId}
Metadatos y conteo por split
GET/api/v1/datasets/{datasetId}/items
Ejemplos paginados
PUT/api/v1/datasets/{datasetId}
Cambia nombre o metadata
DELETE/api/v1/datasets/{datasetId}
Elimina el dataset
GET/api/v1/projects/{projectId}/datasets
Datasets de un proyectoSolo sesión
POST/api/v1/projects/{projectId}/datasets
Crea un dataset vacíoSolo sesión

Las rutas sin marca aceptan API Key. Las dos de /projects/{projectId}/datasets leen con la sesión de la app: con una API Key responden 404.

Formato de los ejemplos

Cada ejemplo es una conversación en ChatML: un objeto con messages, y cada mensaje con role (system, user, assistant o tool) y content. Los mensajes pueden traer tool_calls y name.

conversaciones.jsonl
{"messages": [{"role": "system", "content": "Eres el asistente de ventas de una tienda de muebles."}, {"role": "user", "content": "¿Hacen envíos a Monterrey?"}, {"role": "assistant", "content": "Sí, enviamos a todo México. ¿Me compartes tu código postal para cotizar?"}]}
{"messages": [{"role": "system", "content": "Eres el asistente de ventas de una tienda de muebles."}, {"role": "user", "content": "¿Puedo pagar a meses?"}, {"role": "assistant", "content": "Sí, con tarjeta de crédito participante. ¿Qué producto te interesa?"}]}

Otros formatos (ShareGPT, Alpaca, pares input/output o prompt/completion) se convierten solos si los importas con /ingest. Los detalles de cada formato están en Formatos de importación.

Crear un dataset con sus ejemplos

bash
curl -X POST https://app.astrapp.lat/api/v1/datasets \
  -H "Authorization: Bearer $ASTRAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ventas septiembre",
    "description": "Conversaciones reales del chat de ventas",
    "format": "chatml",
    "items": [
      {"messages": [
        {"role": "user", "content": "¿Hacen envíos a Monterrey?"},
        {"role": "assistant", "content": "Sí, enviamos a todo México."}
      ]}
    ]
  }'
CampoTipoRequeridoDescripción
namestringSíNombre del dataset.
descriptionstringNoDescripción libre.
itemsobject[]NoLos ejemplos. Si todos traen messages, se validan como ChatML.
formatstringNocsv, json, parquet, txt, jsonl o chatml. Cualquier otro valor se guarda como jsonl.
sourcestringNoOrigen del dataset. Por defecto manual.
json
{
  "data": {
    "id": "8d2b6f41-0a3c-4e59-b7d8-21f5c9043ae6",
    "name": "Ventas septiembre",
    "description": "Conversaciones reales del chat de ventas",
    "itemCount": 1,
    "format": "chatml",
    "source": "manual",
    "createdAt": "2026-09-22T10:00:00.000Z",
    "syncedToOpik": false
  },
  "message": "Dataset creado exitosamente"
}
  • El dataset se guarda en el proyecto más antiguo de tu organización; si no tienes ninguno, se crea “Mi primer proyecto”. Esta ruta no recibe projectId.
  • Los ejemplos se reparten por posición: 8 de cada 10 a train, 1 a test y 1 a validation.
  • Si todos los items traen messages, se validan como ChatML y uno inválido hace que la ruta responda 400 con su número. Filas de CSV con un mensaje por fila se agrupan en conversaciones; cualquier otra forma se guarda tal cual, sin convertir. Para convertir otros formatos usa /ingest.

Límite de datasets por plan

Puedes crear hasta 2 datasets con Gratuito, 5 con Starter y 10 con Growth; Professional no tiene límite. Al llegar al tope, la ruta responde 403 con "error": "plan_limit_reached", current y limit.

Importar un archivo

Es lo mismo que hace el asistente de importación de la app: detecta el formato, lo convierte a ChatML y quita duplicados.

bash
jq -n \
  --rawfile text conversaciones.jsonl \
  --arg projectId "$PROJECT_ID" \
  '{text: $text, fileName: "conversaciones.jsonl", projectId: $projectId, datasetName: "Ventas septiembre"}' \
| curl -X POST https://app.astrapp.lat/api/v1/ingest \
  -H "Authorization: Bearer $ASTRAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d @-
CampoTipoRequeridoDescripción
textstringSíEl contenido completo del archivo, como texto.
fileNamestringSíNombre del archivo con extensión; ayuda a detectar el formato.
projectIdstringSíUUID de un proyecto de tu organización.
datasetNamestringNoSi lo mandas, crea un dataset con las conversaciones importadas.
dryRunbooleanNotrue analiza y devuelve una vista previa sin guardar nada.
language'es' | 'en' | 'other'NoIdioma de las conversaciones. Decide los marcadores de la limpieza de datos personales ([TELÉFONO] o [PHONE]). Por defecto es.
redactPiibooleanNoQuita datos personales antes de guardar, y antes de calcular el hash de deduplicación. Por API viene apagado; el asistente lo manda prendido.
parseOptions.businessSenderstringNoParticipante que responde por tu negocio en un chat de WhatsApp o WeChat: sus mensajes se guardan como assistant.
parseOptions.txtMode'whatsapp' | 'role_prefix' | 'alternating'NoCómo interpretar un TXT que no traiga un formato reconocible por contenido.
actions.limitnumberNoMáximo de conversaciones a importar.
actions.splitIntonumberNoParte el dataset en varios de este tamaño.

Las conversaciones entran al proyecto y, si mandaste datasetName, se agrupan en un dataset nuevo. Reimportar el mismo archivo no duplica conversaciones. Esta ruta responde sin sobre data:

json
{
  "summary": {
    "parsed": 2,
    "deduped": 0,
    "errorsFlagged": 0,
    "detectedFormat": "chatml",
    "origin": "imported"
  },
  "imported": 2,
  "created": true,
  "datasetId": "5e0c7a91-2b3d-4f6e-8a1c-9d2e3f4a5b6c",
  "datasetIds": ["5e0c7a91-2b3d-4f6e-8a1c-9d2e3f4a5b6c"],
  "conversationIds": [
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e"
  ],
  "dedupedAgainstPool": 0,
  "limitedByPlan": 0
}

Cuántas conversaciones entran por importación

PlanConversaciones por importación
Gratuito100
Starter500
Growth1,500
ProfessionalSin límite

Si el archivo trae más, se importan las primeras y limitedByPlan dice cuántas quedaron fuera. La ruta admite 10 peticiones por minuto por IP.

Subir un archivo para entrenar

/datasets/upload guarda un archivo en tu almacenamiento y te devuelve su ruta; no crea un dataset. Esa ruta es la que mandas como datasetStoragePath al lanzar un entrenamiento. Acepta multipart/form-data con el campo file y las extensiones json, jsonl, csv, tsv, txt y parquet.

bash
curl -X POST https://app.astrapp.lat/api/v1/datasets/upload \
  -H "Authorization: Bearer $ASTRAPP_API_KEY" \
  -F "[email protected]"
json
{
  "success": true,
  "data": {
    "storagePath": "<tu userId>/datasets/1758535200000-conversaciones.jsonl",
    "sizeBytes": 20480,
    "filename": "conversaciones.jsonl"
  }
}

El límite real del cuerpo es de unos 4.5 MB

Vercel corta el cuerpo de la petición cerca de 4.5 MB antes de que la ruta se ejecute y responde un 413 que no es JSON, aunque el código declare topes mayores. La app limita sus importaciones a 4 MB. Divide los archivos grandes en varias peticiones.

Consultar datasets

Listar

bash
curl "https://app.astrapp.lat/api/v1/datasets?project_id=$PROJECT_ID" \
  -H "Authorization: Bearer $ASTRAPP_API_KEY"

Devuelve { "data": [ … ] } sin paginación. project_id es opcional. El número de ejemplos viene en item_count y también en conversation_count: son el mismo valor con dos nombres, no dos métricas.

Un dataset

json
{
  "data": {
    "id": "8d2b6f41-0a3c-4e59-b7d8-21f5c9043ae6",
    "name": "Ventas septiembre",
    "description": "Conversaciones reales del chat de ventas",
    "format": "chatml",
    "source": "manual",
    "totalItems": 150,
    "metadata": {},
    "huggingfaceId": null,
    "huggingfaceConfig": null,
    "huggingfaceSplit": null,
    "projectId": "3f1a9c2e-5b74-4d81-9e02-7c6a1b4f8d35",
    "createdAt": "2026-09-22T10:00:00.000Z",
    "updatedAt": "2026-09-22T10:05:00.000Z",
    "splits": { "train": 120, "test": 15, "validation": 15 }
  }
}

Sus ejemplos

bash
curl "https://app.astrapp.lat/api/v1/datasets/$DATASET_ID/items?limit=100&offset=0&split=train" \
  -H "Authorization: Bearer $ASTRAPP_API_KEY"

limit va de 50 por defecto a 5,000 como máximo; split es opcional. Cada item trae id, index, split y messages, y la respuesta incluye meta con total, limit, offset y split.

También acepta los filtros de la lista de Conversaciones: search, qa_status (pending, valid, invalid o skipped), has_tools (true o false) y message_length (short, 3 mensajes o menos sin el system, o long). Valen igual para los ejemplos que son referencia a una conversación del proyecto. En un dataset muy grande, un filtro que tarda demasiado responde 503 con el código QUERY_TIMEOUT.

Actualizar y eliminar

PUT /datasets/{datasetId} acepta name, description y metadata; la metadata nueva se combina con la que ya existe. DELETE borra el dataset con todos sus ejemplos de forma permanente y responde { "success": true }.

Ambas rutas, igual que la consulta, verifican que el dataset sea de un proyecto de tu organización o que lo hayas creado tú; si no, responden 403.

Antes de entrenar

Revisa algunos ejemplos, incluye variaciones de las mismas preguntas y cuida que un solo tema no domine el dataset. Los criterios completos están en Calidad.