Importaciones

El importador puebla el padrón desde una sola planilla (CSV o XLSX) con estudiantes, apoderados, Cursos y Generación en las mismas filas. El flujo tiene tres pasos sin estado en el servidor — analyze detecta columnas y propone un mapeo, preview simula, commit escribe — y un contrato de checksum garantiza que los tres pasos hablan del mismo archivo. Todas las rutas exigen el módulo import del plan (si no está licenciado, 403 MODULE_NOT_LICENSED).

El contrato de checksum

analyze calcula el SHA-256 del archivo y lo devuelve como analysis.fileChecksum, ya embebido en analysis.suggestedMapping. preview y commit reciben el archivo de nuevo junto con el mapeo, recalculan el hash y lo comparan con mapping.fileChecksum: si no coinciden, 422 IMPORT_FILE_CHANGED. No hay sesión de importación ni uploadId — el commit re-ejecuta todo el pipeline y nunca confía en un preview anterior; el checksum es la única (y suficiente) garantía de que no se comprometen bytes distintos de los analizados.


POST/api/imports/analyze

Analizar la planilla

Requiere subjects.write. multipart/form-data con un único campo file (CSV o XLSX, máximo 5 MB). Detecta delimitador y codificación, clasifica cada columna con su confianza, reconoce la forma de los apoderados (wide: columnas apoderado 1/2; long: una fila por vínculo) y detecta si los nombres de hoja parecen Cursos (1°A, 1°B). La joya es suggestedMapping: un mapeo completo listo para reenviar a preview.

Errores propios

  • Nombre
    IMPORT_FILE_TYPE_UNSUPPORTED
    Tipo
    400
    Descripción

    Ni CSV ni XLSX.

  • Nombre
    IMPORT_FILE_TOO_LARGE
    Tipo
    400
    Descripción

    Más de 5 MB.

Solicitud

POST
/api/imports/analyze
curl -X POST "https://app.edugoverna.com/api/imports/analyze" \
  -H "x-api-key: {tu_api_key}" \
  -F "file=@matriculas-2026.xlsx"

Respuesta (recortada)

{
  "analysis": {
    "fileChecksum": "0f2a…64-hex…",
    "kind": "xlsx",
    "delimiter": null,
    "encoding": "utf-8",
    "sheets": [
      {
        "name": "1°A",
        "rowCount": 33,
        "headers": ["RUT", "Nombres", "Apellidos", "…"],
        "suggestedInclude": true,
        "sheetNameLooksLikeCurso": true
      }
    ],
    "columns": [
      {
        "sourceIndex": 0,
        "sourceHeader": "RUT",
        "suggestedTarget": "student.rut",
        "confidence": "high",
        "alternatives": []
      }
    ],
    "guardianShape": { "detected": "wide", "confidence": "high" },
    "suggestedMapping": {
      "fileChecksum": "0f2a…64-hex…",
      "guardianShape": "wide",
      "sheets": [{ "name": "1°A", "include": true }],
      "columns": [{ "sourceIndex": 0, "sourceHeader": "RUT", "target": "student.rut" }],
      "cursoSource": { "type": "sheetName" },
      "generacion": { "type": "none" },
      "defaults": { "relationshipType": "apoderado" }
    },
    "warnings": []
  }
}

POST/api/imports/preview

Previsualizar

multipart/form-data con file (los mismos bytes) y mapping (el ImportMapping como string JSON — normalmente el suggestedMapping, ajustado). Simula la importación completa sin escribir nada: totales de altas/actualizaciones/errores, el veredicto fila a fila, y el plan de Cursos — qué nombre de origen cae en qué segmento existente y cuáles habría que crear.

Para que commit pueda crear un Curso nuevo, su sourceName debe venir autorizado en mapping.approvedCursoCreations; si no, 422 IMPORT_CURSO_NOT_APPROVED. Así una hoja mal nombrada no acuña cursos por accidente.

Solicitud

POST
/api/imports/preview
curl -X POST "https://app.edugoverna.com/api/imports/preview" \
  -H "x-api-key: {tu_api_key}" \
  -F "file=@matriculas-2026.xlsx" \
  -F 'mapping={"fileChecksum":"0f2a…", "guardianShape":"wide", …}'

Respuesta (recortada)

{
  "preview": {
    "totals": {
      "students": { "new": 31, "update": 2, "error": 0 },
      "guardians": { "new": 54, "update": 3, "error": 1 },
      "guardianships": { "new": 55, "update": 0, "error": 1 }
    },
    "rows": [
      {
        "sheetName": "1°A",
        "line": 2,
        "status": "new",
        "rut": "23456789-6",
        "studentName": "Martina Rojas Fuentes",
        "guardianNames": ["Carolina Fuentes"],
        "cursoName": "1°A",
        "warnings": []
      }
    ],
    "cursoPlan": [
      { "sourceName": "1°A", "resolution": { "type": "create" }, "studentCount": 33 }
    ],
    "ignoredColumns": [],
    "sheetErrors": []
  }
}

POST/api/imports/commit

Confirmar

Mismo cuerpo que preview más el campo opcional rowStart: el commit escribe en tramos de 40 filas y result.progress te dice si queda otro tramo por pedir. El resultado detalla fila a fila qué se creó, actualizó o falló, más los reportes de Cursos y Generación.

Solicitud

POST
/api/imports/commit
curl -X POST "https://app.edugoverna.com/api/imports/commit" \
  -H "x-api-key: {tu_api_key}" \
  -F "file=@matriculas-2026.xlsx" \
  -F 'mapping={"fileChecksum":"0f2a…", …}' \
  -F "rowStart=0"

Respuesta (recortada)

{
  "result": {
    "students": { "created": 31, "updated": 2, "failed": 0, "skipped": 0 },
    "guardians": { "created": 54, "updated": 3, "failed": 1 },
    "guardianships": { "created": 55, "updated": 0, "failed": 1 },
    "rows": [
      {
        "sheetName": "1°A",
        "line": 2,
        "outcome": "created",
        "subjectId": "3f6f…",
        "rut": "23456789-6",
        "warnings": []
      }
    ],
    "issues": [],
    "cursoReport": [
      { "sourceName": "1°A", "segmentId": "5b2c…", "created": true, "added": 33 }
    ],
    "progress": { "totalRows": 33, "rangeStart": 0, "rangeEnd": 33, "done": true }
  }
}

GET/api/imports/template.xlsx

Plantilla oficial

GET /imports/template.xlsx descarga la planilla de ejemplo (plantilla-estudiantes.xlsx). Está garantizado por contrato que la plantilla pasa por analyze sin advertencias y con todas sus columnas detectadas en confianza high — es el punto de partida recomendado para los colegios.


Padrones compartidos y registradores externos

Cuando quien tiene la nómina no es el colegio (un club, una academia, un fotógrafo), el padrón entra por registradores externos: se les envía una invitación y ellos cargan su registro en un portal público con el mismo importador. Desde la API de organización se administra la relación, no la carga:

Método y rutaPermisoQué hace
GET /registrar-invitesregistrar_invites.manageInvitaciones enviadas, con estado (pending, expired, aceptadas con su registryOrganizationId).
POST /registrar-invitesregistrar_invites.manageInvita a un registrador externo por correo.
POST /registrar-invites/:inviteId/resendregistrar_invites.manageReenvía la invitación.
DELETE /registrar-invites/:inviteIdregistrar_invites.manageCancela la invitación.
GET /registry-sharesregistry_shares.readLos padrones que tú compartiste como dueño: grupo, estado, memberCount, campañas y solicitudes asociadas; los compartidos contigo llegan por GET /shared-sources.
POST /registry-shares · PATCH · DELETEregistry_shares.writeOtorga, ajusta o revoca un share (por Curso: N shares por registro).
GET /shared-sourcesshared_subjects.readLas fuentes compartidas y sus titulares, para campañas sobre padrón ajeno.

Las campañas de consentimiento sobre padrones compartidos están documentadas en Consentimientos y en la guía de campañas compartidas.

¿Te sirvió esta página?