Documentación de la API de YA-Planning
Integre la generación y consulta de horarios, gestione la configuración de sus centros y reciba eventos en tiempo real. Referencia completa, ejemplos y entorno de pruebas.
Introducción
La API es REST, en JSON, versionada. Todos los recursos de negocio viven bajo el prefijo /api/v1/pub/v1. Los endpoints de demostración públicos están en /api/v1/public/api-demo.
- Base URL:
https://su-dominio/api/v1/pub/v1 - Formato: solicitudes y respuestas en
application/json(salvo exportaciones ICS/PDF). - Versionado: la versión está en la ruta (
/v1); las adiciones retrocompatibles no cambian la versión. - CORS: la API pública está abierta a aplicaciones de navegador de terceros (sin cookies).
Autenticación
Cada solicitud lleva una clave API, en una de las dos cabeceras:
X-API-Key: yap_live_xxxxxxxxxxxxxxxxxxxx
# ou
Authorization: Bearer yap_live_xxxxxxxxxxxxxxxxxxxxUna clave puede estar autorizada para varios centros (clave empresa). Indique entonces el destino mediante la cabecera X-Etablissement-Id; si solo hay un centro autorizado, se deduce automáticamente. Las claves se crean, con ámbitos, en la consola.
Entornos y entorno de pruebas
Dos entornos, distinguidos por el prefijo de la clave:
yap_live_…— producción: sus datos reales; la generación descuenta de la cuota semanal.yap_test_…— sandbox: las lecturas devuelven un conjunto de datos de demostración (nunca sus datos reales), la generación no se descuenta, y la escritura de configuración se rechaza (SANDBOX_READONLY). Ideal para desarrollar sin riesgo.
Ámbitos
Cada clave lleva un subconjunto de ámbitos; un endpoint rechaza (403 INSUFFICIENT_SCOPE) si falta el ámbito requerido.
config:read | Leer ciclos, clases, asignaturas, profesores, franjas, volúmenes horarios. |
config:write | Crear / modificar / eliminar la configuración del centro. |
timetables:read | Listar los trabajos, leer los resultados y los horarios publicados, exportar. |
timetables:write | Lanzar una generación y publicar un horario. |
webhooks:manage | Crear, listar y eliminar endpoints webhook. |
establishments:manage | Crear y listar sus propios centros (nivel cuenta, sin X-Etablissement-Id). |
Límite y cuotas
Cada clave tiene un límite de velocidad (60 req/min por defecto). Las respuestas llevan:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1783919311 # epoch (s) de réinitialisationSuperarlo devuelve 429 RATE_LIMITED con la cabecera Retry-After. La generación de horarios está además sujeta a la cuota semanal del plan (visible mediante /me).
Toda respuesta de la API lleva también una cabecera X-Request-Id (identificador de correlación) — comuníquelo al soporte en caso de incidencia. Nota: el conteo de velocidad se aplica actualmente por instancia; en un despliegue multiinstancia el límite efectivo puede ser un múltiplo del valor mostrado.
Errores
Envoltura de error uniforme, con un requestId para el soporte:
{ "error": "INSUFFICIENT_SCOPE", "message": "Scope requis : config:write.",
"requestId": "6181762d-…", "requiredScope": "config:write" }| Código | error | Causa |
|---|---|---|
| 400 | BAD_REQUEST | Parámetros ausentes o inválidos. |
| 401 | UNAUTHORIZED / INVALID_API_KEY | Clave ausente, inválida o revocada. |
| 403 | INSUFFICIENT_SCOPE | La clave no posee el ámbito requerido. |
| 403 | ETABLISSEMENT_NOT_GRANTED | La clave no está autorizada para el centro solicitado. |
| 403 | SANDBOX_READONLY | Escritura prohibida con una clave sandbox (solo lectura). |
| 402 | PLAN_UPGRADE_REQUIRED | Función reservada a un plan de pago (p. ej. exportación iCal). |
| 404 | NOT_FOUND | Recurso inexistente o fuera de su centro. |
| 409 | WORKFLOW_ERROR | Transición de flujo imposible (p. ej. publicar un borrador). |
| 429 | RATE_LIMITED | Velocidad superada — reintente tras la cabecera Retry-After. |
Probar en directo — sin registro
Endpoints de demostración públicos (no se requiere clave).
Postman: «Import» → «Link» → pegue /q/openapi?format=json.
Referencia — Cuenta e introspección
/meDetalles de la clave actual: entorno, centro destino, ámbitos concedidos y cuota de generación restante. No requiere ámbito.
{
"environment": "LIVE",
"etablissementId": "61a9…8cb",
"scopes": ["config:read", "timetables:write"],
"entitlements": {
"plan": "PRO",
"generationsRestantes": -1,
"resetLe": "2026-07-14T00:00:00Z",
"maxClassesExport": -1
}
}/me/etablissementPerfil público del centro destino: nombre, sigla, ciudad, país, tipo, sitio web. No requiere ámbito.
{"id":"…","nom":"Groupe Scolaire Les Palmiers","slug":"gs-palmiers","sigle":"GSP","ville":"Abidjan","pays":"CI","type":"PRIVE","siteWeb":"https://…"}/me/usageUso reciente de la clave actual (llamadas y errores por día). No requiere ámbito.
days— ventana en días (por defecto 30, máx 90)
{"apiKeyId":"…","days":30,"daily":[{"day":"2026-07-12","calls":128,"errors":3}]}Referencia — Cuenta — centros
Aprovisionamiento a nivel de cuenta: cree sus propios centros SIN la cabecera X-Etablissement-Id (la ruta /account no está vinculada a un centro). Ámbito establishments:manage. Al crear, la clave llamante recibe automáticamente una concesión ACTIVE sobre el nuevo centro — luego use X-Etablissement-Id para configurarlo y generar.
/account/etablissementsestablishments:manageCrear un centro (bucket de desarrollador, sujeto al tope de su cuenta).
{"nom":"Groupe Scolaire Les Palmiers","type":"PRIVE_LAIC","pays":"CI"}{"id":"…","nom":"Groupe Scolaire Les Palmiers","slug":"gs-les-palmiers","pays":"CI","type":"PRIVE_LAIC"}/account/etablissementsestablishments:manageListar los centros que ha creado.
[{"id":"…","nom":"…","slug":"…","pays":"CI","type":"PRIVE_LAIC"}]Referencia — Configuración
Estructura pedagógica del centro. Lectura: ámbito config:read. Escritura: ámbito config:write (prohibida en sandbox). Un centro recién creado ya contiene un «Ciclo principal».
/cyclesconfig:readLista de ciclos.
[{"id":"…","libelle":"Cycle principal","ordre":0}]/cyclesconfig:writeCrear un ciclo.
{"libelle":"Second cycle","ordre":1}/cycles/{id}config:writeEliminar un ciclo.
/niveauxconfig:readLista de clases/niveles.
[{"id":"…","libelle":"6ème 1","cycleId":"…","effectif":42,"ordre":1}]/niveauxconfig:writeCrear una clase.
{"libelle":"6ème 3","cycleId":"<uuid-cycle>","effectif":40,"ordre":3}/niveaux/{id}config:writeModificar una clase (campos parciales).
/niveaux/{id}config:writeEliminar una clase.
/disciplinesconfig:readLista de asignaturas.
[{"id":"…","libelle":"Mathématiques","code":"MATH","couleur":"#6C5CE7","ordre":1}]/disciplinesconfig:writeCrear una asignatura.
{"libelle":"Physique-Chimie","code":"PC","couleur":"#00B894","ordre":5}/disciplines/{id}config:writeModificar una asignatura.
/disciplines/{id}config:writeEliminar una asignatura.
/professeursconfig:readLista de profesores.
[{"id":"…","nom":"Koné","prenoms":"Awa","matricule":"P-0142","email":"…","telephone":"…","nombreHeureAutorise":18,"statut":"TITULAIRE","actif":true}]/professeursconfig:writeCrear un profesor.
{"nom":"Diarra","prenoms":"Sékou","matricule":"P-0210","email":"s.diarra@ecole.ci","nombreHeureAutorise":18,"statut":"VACATAIRE","actif":true}/professeurs/{id}config:writeModificar un profesor.
/professeurs/{id}config:writeEliminar un profesor.
/horairesconfig:readFranjas horarias de la cuadrícula.
[{"id":"…","jour":"MONDAY","heureDebut":"08:00","heureFin":"09:00","estPause":false,"libelle":null}]/horairesconfig:writeCrear una franja (día, HH:mm).
{"jour":"MONDAY","heureDebut":"08:00","heureFin":"09:00","estPause":false,"libelle":"M1"}/horaires/{id}config:writeEliminar una franja.
/volumesconfig:readVolúmenes horarios (asignatura × ciclo).
[{"id":"…","cycleId":"…","disciplineId":"…","nombreHeuresObligatoire":4,"minHeuresConsecutives":1,"maxHeuresConsecutives":2}]/volumesconfig:writeCrear un volumen horario.
{"cycleId":"<uuid>","disciplineId":"<uuid>","nombreHeuresObligatoire":4,"minHeuresConsecutives":1,"maxHeuresConsecutives":2}/volumes/{id}config:writeEliminar un volumen horario.
Referencia — Horarios
Generación asíncrona (el solver corre en segundo plano — consulte el estado), publicación y consulta. En sandbox, la generación usa un conjunto de demostración y no se descuenta de la cuota.
/timetables/generatetimetables:writeLanza una generación. Devuelve 202 + un jobId a consultar. LIVE descuenta de la cuota semanal. Cabecera opcional Idempotency-Key: un mismo identificador reproduce la respuesta memorizada (respuesta marcada Idempotency-Replayed: true) en lugar de relanzar una generación.
Idempotency-Key— cabecera (opcional) — clave de idempotencia en LIVE
{"durationMinutes": 5}{"jobId":"…","status":"SOLVING_SCHEDULED"}/timetables/jobstimetables:readLista paginada de los trabajos.
page— índice de página (por defecto 0)size— tamaño (por defecto 25, máx 100)
{"items":[{"jobId":"…","name":"…","status":"SOLVING_ENDED","workflowStatus":"BROUILLON","feasible":true,"hardScore":0,"softScore":-42,"createdAt":"…"}],"total":7,"page":0,"size":25}/timetables/jobs/{jobId}timetables:readEstado de un trabajo.
/timetables/jobs/{jobId}/resulttimetables:readResultado: lista de lecciones (una vez status = SOLVING_ENDED).
{"jobId":"…","status":"SOLVING_ENDED","feasible":true,"lessons":[{"id":"1","matiere":"Maths","niveau":"6ème 1","professeur":"M. Koné","jour":"MONDAY","debut":"08:00:00","fin":"09:00:00","couleur":"#6C5CE7","niveauOrdre":1,"verrouille":false}]}/timetables/jobs/{jobId}/publishtimetables:writePublica el horario (workflow → PUBLIE). Dispara el evento webhook timetable.published.
/timetables/published/latesttimetables:readÚltimo horario publicado del centro.
/timetables/published/{jobId}/classestimetables:readEtiquetas de las clases presentes en un horario publicado.
{"classes":["6ème 1","6ème 2","5ème 1"]}/timetables/published/{jobId}/classe/{niveau}timetables:readLecciones de una clase de un horario publicado.
/timetables/jobs/{jobId}/export.icstimetables:readExportación iCalendar (text/calendar). Reservada al plan Pro → 402 en caso contrario.
niveau— filtrar por una claseprofesseur— filtrar por un profesor
/timetables/jobs/{jobId}/export.pdftimetables:readExportación PDF (application/pdf) — toda la promoción, por clase o por profesor.
mode— all | class | teacherniveau— requerido si mode=classprofesseur— requerido si mode=teacher
Referencia — Webhooks
Reciba eventos firmados. Ámbito webhooks:manage. El secreto solo se devuelve en la creación (o tras la rotación). Eventos: timetable.job.completed, timetable.job.failed, timetable.published, webhook.test. Cada entrega se firma (HMAC-SHA256) y se reproduce hasta 5 veces en caso de fallo. La URL se valida contra SSRF (destinos internos/privados rechazados).
/webhookswebhooks:manageLista de endpoints.
/webhookswebhooks:manageCrear un endpoint. Devuelve el secreto de firma (consérvelo).
{"url":"https://exemple.com/webhooks/yap","events":["timetable.published","timetable.job.completed"]}{"endpoint":{"id":"…","url":"…","events":["timetable.published"],"active":true},"secret":"whsec_…"}/webhooks/{id}webhooks:manageEliminar un endpoint.
/webhooks/{id}/deliverieswebhooks:manageRegistro de entregas (estado, código HTTP, intentos).
/webhooks/{id}/rotatewebhooks:manageRegenerar el secreto de firma (devuelto una sola vez).
{"endpoint":{"id":"…","url":"…"},"secret":"whsec_…"}/webhooks/{id}/testwebhooks:manageEnviar un evento webhook.test al endpoint (202 + status queued).
/webhooks/deliveries/{deliveryId}/replaywebhooks:manageReproducir una entrega pasada (202 + status queued).
Referencia — Demo (pública, sin clave)
Endpoints públicos no autenticados para descubrir la forma de las respuestas.
/api/v1/public/api-demo/previewVista previa de un centro de demostración (ciclos, clases, asignaturas, profesores, franjas).
/api/v1/public/api-demo/sample-timetableEjemplo de lecciones (forma de un horario generado).
Webhooks — verificar una firma
Cada entrega es un POST JSON con las cabeceras X-Webhook-Event, X-Webhook-Timestamp y X-Webhook-Signature = HMAC-SHA256(timestamp + "." + body, secret). Verifique la firma y la frescura del timestamp (menos de 5 min) para evitar la reproducción. Eventos: timetable.published, timetable.job.completed, timetable.job.failed, webhook.test.
POST https://votre-app/webhook
X-Webhook-Event: timetable.published
X-Webhook-Timestamp: 1712345678
X-Webhook-Signature: 9f86d081…
{ "event":"timetable.published", "jobId":"…", "etablissementId":"…", "occurredAt":"…" }import crypto from "crypto";
// Express — vérifier la signature d'un webhook YA-Planning
app.post("/webhooks/yap", express.raw({ type: "*/*" }), (req, res) => {
const ts = req.header("X-Webhook-Timestamp");
const sig = req.header("X-Webhook-Signature");
const body = req.body.toString("utf8");
const expected = crypto.createHmac("sha256", process.env.YAP_WEBHOOK_SECRET)
.update(`${ts}.${body}`).digest("hex");
// fraîcheur (anti-rejeu) : < 5 min
const fresh = Math.abs(Date.now()/1000 - Number(ts)) < 300;
if (!fresh || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
return res.sendStatus(400);
const event = JSON.parse(body); // { event, jobId, etablissementId, occurredAt }
res.sendStatus(200);
});Ejemplos de código
# Vérifier ses droits
curl https://votre-domaine/api/v1/pub/v1/me \
-H "X-API-Key: yap_live_xxxxxxxxxxxx"
# Générer un EDT puis suivre le job
JOB=$(curl -s -X POST .../api/v1/pub/v1/timetables/generate \
-H "X-API-Key: yap_live_xxxx" -H "Content-Type: application/json" \
-d '{"durationMinutes":5}' | jq -r .jobId)
curl .../api/v1/pub/v1/timetables/jobs/$JOB \
-H "X-API-Key: yap_live_xxxx"Versiones y obsolescencia
La API está versionada en la ruta (/api/v1/pub/v1/…). Añadimos campos y endpoints de forma retrocompatible; estas adiciones no constituyen una ruptura, así que programe de forma tolerante (ignore los campos desconocidos). Toda ruptura dará lugar a una nueva versión mayor y a un preaviso de 90 días mínimo, anunciado mediante la cabecera de respuesta Deprecation y el registro de cambios a continuación.
2026-07— Cuentas de desarrollador y panel; aprovisionamiento a nivel de cuenta (POST /account/etablissements, ámbitoestablishments:manage); endpoints/cycles; exportación PDFmode=teacher.2026-07— Idempotency-Key en la generación; endpoints/me/etablissement,/me/usage; rotación / prueba / reproducción de webhooks; eventotimetable.job.failed; cabeceraX-Request-Id; paginación de las listas de configuración; expiración y restricción de IP de las claves; validación anti-SSRF de las URL de webhook.2026-06— Lanzamiento de la API pública v1: claves con ámbitos, configuración, generación y publicación de horarios, webhooks firmados, sandbox, cabeceras de cuota.
¿Listo para integrar?
Cree una clave sandbox en 30 segundos y haga su primera llamada.
Abrir la consola API