Integración de partners

Documentación operativa del canal de distribución para el integrador externo: cómo se contratan asientos, cómo se dan de alta los alumnos y qué datos devuelve la plataforma. Es material técnico para quien firma un contrato de partner, no una oferta comercial.

Referencia completa de la API

Qué da el canal

Un contrato con IAcademy define dos cosas: una quota de asientos (max_active_seats, el número máximo de alumnos activos a la vez) y un tier de acceso (pro o premium, nunca mezclas). El partner da de alta alumnos por API; el alumno entra con su propio login y el asiento se activa. El partner pinta su propuesta con el catálogo que le corresponde por tier y recibe reporting solo de agregados.

Cómo se entra: la clave de API

Todas las rutas viven bajo https://api.ia-academy.io/api/partner/v1/ y exigen la cabecera X-Api-Key en cada llamada, también en las de lectura. La clave se entrega una sola vez con la firma del contrato y no se puede volver a consultar: en base de datos solo queda el hash (SHA-256). Si la clave se pierde, la solución es dar de alta un partner nuevo, no recuperar la anterior. Una clave suspendida y una clave inexistente responden igual: la plataforma no enumera partners.

La API: seis endpoints

El contrato técnico es la especificación OpenAPI; es la fuente que prevalece si este documento y ella difieren. Consúltala en la Referencia completa de la API. Los errores van como {detail} legible o {code, message} (caso de quota).

1. GET /catalog: catálogo con visibilidad por tier

Cada curso y unidad del catálogo, con el campo tier_required que dice qué tier mínimo abre la unidad. Con eso el partner compara el tier de su contrato y pinta su árbol con la visibilidad real. No hay URLs de media ni contenido de lecciones: eso vive tras la sesión del alumno en app.ia-academy.io.

curl -sS "https://api.ia-academy.io/api/partner/v1/catalog" \
  -H "X-Api-Key: <tu-clave>"

2. POST /learners: crear asientos (bulk, idempotente)

De 1 a 500 alumnos por llamada. Cada alumno se identifica por partner_learner_id (el identificador tuyo; el de IAcademy se queda en la base de datos aquí) y, si lo conoces, por email, que pre-vincula y hace que el claim del alumno no espere a su primera sesión. La operación es idempotente: repetir el mismo partner_learner_id re-declara el asiento; reactivated: true revive uno revocado antes. La quota es dura: si el lote no cabe entero, falla entero con 409 quota_exceeded, sin alta parcial.

curl -sS -X POST "https://api.ia-academy.io/api/partner/v1/learners" \
  -H "X-Api-Key: <tu-clave>" \
  -H "Content-Type: application/json" \
  -d '{"learners":[{"partner_learner_id":"ws-12345","email":"[email protected]"}]}'

3. GET /learners: listar asientos

Todos los asientos del contrato, de más antiguo a más nuevo. Paginación con limit (1-500, por defecto 100) y offset.

curl -sS "https://api.ia-academy.io/api/partner/v1/learners?limit=100&offset=0" \
  -H "X-Api-Key: <tu-clave>"

4. GET /learners/{partner_learner_id}: estado de un asiento

Respuestas: active, revoked (con revoked_reason, el motivo que el partner escribió al revocar) o expired (el contrato acabó). Un id que nunca se dió de alta devuelve 404: el estado no se adivina.

curl -sS "https://api.ia-academy.io/api/partner/v1/learners/ws-12345" \
  -H "X-Api-Key: <tu-clave>"

5. DELETE /learners/{partner_learner_id}: liberar un asiento

Sirve para reutilizar el hueco cuando alguien deja la empresa cliente o hay que corregir un pedido: el asiento se libera y se puede dar de alta a un alumno distinto. El cuerpo lleva un campo reason obligatorio (3-500 caracteres), que queda en la auditoría. Idempotente: revocar lo ya revocado responde igual. Sin reembolsos: liberar el asiento es el único movimiento; es una decisión de producto.

curl -sS -X DELETE "https://api.ia-academy.io/api/partner/v1/learners/ws-12345" \
  -H "X-Api-Key: <tu-clave>" \
  -H "Content-Type: application/json" \
  -d '{"reason":"left the company"}'

6. GET /reporting: agregados L0

Solo agregados, sin dato personal de ningún alumno: seats_contracted, seats_active, seats_activate_rate (activos / contratados; la cifra que dice si el canal funciona), learners_login, quizzes_passed, certificates.

curl -sS "https://api.ia-academy.io/api/partner/v1/reporting" \
  -H "X-Api-Key: <tu-clave>"

Ninguna ruta de partner cambia el contrato ni la clave: eso lo gestiona IAcademy desde su admin (el alta devuelve la clave en claro una vez; la suspensión expira los asientos en vivo). Requiere sesión admin de IAcademy, no la clave del partner.

Qué hace el alumno: el claim de asiento

El alumno de empresa nunca recibe un código de compra:

  1. El partner graba el asiento por API (con partner_learner_id, y con el email si lo quiere pre-vincular).
  2. El alumno entra con su propio login (OIDC) en https://app.ia-academy.io en su propia cuenta; si el partner ya le dió el email en el alta, la cuenta se casa en ese primer login.
  3. La app llama internamente a POST /api/auth/claim-seat con la sesión del alumno: eso convierte esa sesión en acceso al curso. Idempotente: un segundo claim responde igual.
  4. Un 409 de asiento de partner puede venir de asiento revocado o de contrato caducado: lo decide el partner, no el alumno. El claim también tiene rate limit: 10 intentos por 10 minutos por cuenta.

El alumno acepta además la política de privacidad de IAcademy en su alta; el texto legal ya recoge que su empresa o proveedor accede a progreso agregado.

Errores y rate limit

HTTPCuándo ocurreEjemplo de cuerpo
401Falta la cabecera X-Api-Key, clave inválida o partner suspendido: misma respuesta en los tres casos, para no enumerar partners.{"detail":"Clave de partner invalida"}
409El lote de POST /learners no cabe entero en la quota del contrato; no se da de alta nada parcialmente.{"detail":{"code":"quota_exceeded","message":"..."}}
404El partner_learner_id consultado no existe en ese contrato.{"detail":"Ese alumno no existe en el contrato"}
422Entrada que no valida contra el OpenAPI: email demasiado largo, límite fuera de rango, campo que falta.{"detail":[...]}
429Rate limit por partner en cada ruta, lectura o escritura (también en el claim del alumno: 10 intentos / 10 min por cuenta).{"detail":"Demasiadas peticiones; espera un minuto"}

La quota contratada solo se consulta (y se respeta) en el alta de asientos: cuando un lote no cabe, devolvemos 409 con el detalle de la quota. Prevenirlo: GET /learners + contar los active.

Datos del alumno: niveles L0 / L1 / L2

El principio de partida: el partner es responsable de sus alumnos; a IAcademy le llegan como una lista que vosotros gestionáis. Tres niveles de visibilidad:

NivelQué devuelveCuándo
L0 (defecto; es lo que da GET /reporting hoy)Agregados: nº de asientos activos, tasa de activación, medias de score, nº de certificados.Fase 1: canal en producción
L1 (opt-in del partner)Por alumno: partner_learner_id, estado active/revoked/expired, módulos completados, score del último quiz, última actividad, credentials.public_id verificable.Fase 2: dashboard que el partner pinta a su empresa cliente
L2 (futuro)Email del alumno (como identidad que el partner ya posee, no como dato personal que IAcademy devuelve).Solo bajo contrato explícito

Lo que jamás se devuelve al partner: el nombre real del alumno, su dirección IP, el histórico de preguntas y respuestas, ni las conversaciones con el tutor (ni las notas del Tutor+). Ni como reporting en ningún nivel, ni bajo opt-in.

Siguiente paso

Para empezar

Si tu organización quiere ser partner de distribución, escríbenos y cerramos el contrato (tiers, quota y facturación). Con la firma se entrega la clave de API, una sola vez y en texto plano.

[email protected]