Limiti di frequenza
Ogni applicazione ha un numero di richieste al minuto scelto dal dirigente (30, 60, 120, 300; predefinito 60), comprese le richieste di token. Ogni risposta riporta X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset (secondi alla ripartenza). Oltre il limite la risposta è 429 con Retry-After in secondi: aspetta e riprova. Con il servizio in manutenzione la risposta è 503, anch'essa con Retry-After.
Errori
Gli errori sono oggetti Problem (RFC 9457, application/problem+json): type rimanda alla spiegazione qui sotto, instance identifica la richiesta (da comunicare al supporto). Gli errori di /oauth/token hanno anche error ed error_description di OAuth 2.0. Per non dare indizi, credenziali sbagliate, revocate o scadute danno lo stesso errore.
HTTP/1.1 403 Forbidden
Content-Type: application/problem+json; charset=utf-8
WWW-Authenticate: Bearer realm="didattiko", error="insufficient_scope", scope="grades:read"
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 41
{
"type": "https://prova.didattiko.com/sviluppatori#errore-ambito-mancante",
"title": "Ambito non concesso",
"status": 403,
"detail": "Serve l'ambito «grades:read».",
"instance": "urn:uuid:3f0c7a52-8d1e-4c43-a6c1-2b8e1a0f9d11",
"requiredScope": "grades:read"
}
| Stato | Tipo | Quando |
|---|
| 400 | Richiesta non valida errore-richiesta-non-valida | Un parametro manca, è sconosciuto o ha un valore non valido: il campo «detail» dice quale. |
|---|
| 401 | Credenziali non valide errore-credenziali-non-valide | client_id o client_secret sbagliati, applicazione revocata o scaduta. Per sicurezza non si dice quale dei casi. |
|---|
| 401 | Token mancante errore-token-mancante | Serve l'intestazione «Authorization: Bearer <token>» con un token ottenuto da /oauth/token. |
|---|
| 401 | Token non valido o scaduto errore-token-non-valido | Il token è scaduto (dura 15 minuti), è sbagliato o l'applicazione è stata revocata: chiedine uno nuovo. |
|---|
| 403 | Ambito non concesso errore-ambito-mancante | L'applicazione non ha l'ambito (scope) richiesto dall'operazione: il dirigente può crearne una con gli ambiti giusti. |
|---|
| 403 | Rete non consentita errore-rete-non-consentita | L'applicazione può chiamare solo dagli indirizzi indicati dal dirigente alla creazione. |
|---|
| 404 | Risorsa non trovata errore-non-trovato | La risorsa non esiste o appartiene a un'altra scuola. |
|---|
| 405 | Metodo non consentito errore-metodo-non-consentito | L'API è in sola lettura: si usa GET (POST solo per /oauth/token). |
|---|
| 415 | Tipo di contenuto non supportato errore-tipo-non-supportato | /oauth/token accetta solo application/x-www-form-urlencoded. |
|---|
| 429 | Troppe richieste errore-troppe-richieste | Superato il limite di richieste al minuto dell'applicazione: riprova dopo i secondi indicati in «Retry-After». |
|---|
| 403 | Serve HTTPS errore-https-obbligatorio | In produzione l'API risponde solo su connessioni cifrate (TLS). |
|---|
| 500 | Errore interno errore-errore-interno | Errore imprevisto del server: riprova; se si ripete, comunica l'identificativo «instance» al supporto. |
|---|
| 503 | Servizio non disponibile errore-servizio-non-disponibile | Il servizio è in manutenzione o sovraccarico: riprova dopo i secondi indicati in «Retry-After». |
|---|
Webhook (in preparazione)
Non ancora attivi Con i webhook il registro avviserà da solo il programma, invece di aspettare che chieda. Il dirigente sceglierà l'indirizzo https che riceve e gli eventi, tra quelli coperti dagli ambiti dell'applicazione:
attendance.recorded — Un evento di presenza appena registrato (stessi campi di /attendance: mai motivi o note). Ambito attendance:read.grade.published — Un voto appena diventato visibile alla famiglia (stessi campi di /grades; mai religione e attività alternativa). Ambito grades:read.homework.created — Un compito per tutta la classe appena inserito (stessi campi di /homework). Ambito agenda:read.
Ogni avviso è una POST in JSON firmata secondo Standard Webhooks: intestazioni webhook-id (uguale nei nuovi tentativi: serve a scartare i doppioni), webhook-timestamp (secondi Unix) e webhook-signature = v1, + base64 di HMAC-SHA256 di id.timestamp.corpo con la chiave della firma (whsec_…, mostrata una volta sola). Il programma risponde con uno stato 2xx entro 10 secondi; altrimenti il registro riprova dopo 1 minuto, 5 minuti, 30 minuti, 2, 6, 12 e 24 ore.
POST /didattiko HTTP/1.1
Content-Type: application/json; charset=utf-8
webhook-id: msg_2KWPBgLlAfxdpx2AI54pPJ
webhook-timestamp: 1792652400
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"type": "attendance.recorded",
"timestamp": "2026-10-22T07:40:00Z",
"data": {
"id": "cm2x7k0a90001qw8z3l5d4f6h",
"studentId": "cm2x7k0a90002qw8z9k1d2e3f",
"classId": "cm2x7k0a90003qw8z4m5n6o7p",
"date": "2026-10-22",
"type": "RITARDO",
"at": "2026-10-22T09:10:00+02:00",
"hour": 2,
"hourTo": null,
"justificationStatus": "NONE",
"shortDelay": false,
"recordedAt": "2026-10-22T07:12:30Z"
}
}
// Verifica della firma (Node.js) — oppure la libreria "standardwebhooks" per molti linguaggi
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(secret, headers, body) {
const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // al massimo 5 minuti di scarto
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${ts}.${body}`).digest();
return headers["webhook-signature"].split(" ").some((s) => {
const [v, sig] = s.split(",");
const got = Buffer.from(sig ?? "", "base64");
return v === "v1" && got.length === expected.length && timingSafeEqual(got, expected);
});
}
Dati che non escono mai
L'API è pensata per i dati minimi (art. 5 e 25 GDPR). Non restituisce, con nessun ambito:
- dati sanitari, diete, certificazioni, PEI, PDP, PFI e ogni altro dato dell'inclusione; docenti, ore e materia di sostegno;
- note disciplinari, richiami, provvedimenti; motivi, causali e deroghe delle assenze; motivo del fuori classe;
- commenti e annotazioni riservate dei voti, voti di religione cattolica e attività alternativa (rivelerebbero la scelta religiosa);
- parte dell'agenda riservata ai docenti, compiti e voci d'agenda per singoli alunni;
- codici fiscali, date di nascita, indirizzi, telefoni ed e-mail delle persone, tutori e deleghe;
- i dettagli delle operazioni nel registro attività.
Versioni e supporto
La versione maggiore è nell'indirizzo (/api/v1), quella completa (Semantic Versioning) nella specifica: oggi 1.0.0. Dentro la v1 si aggiungono solo operazioni, parametri facoltativi e proprietà: i programmi devono ignorare le proprietà che non conoscono. Un cambiamento incompatibile diventa /api/v2, annunciato almeno un mese prima, con la v1 attiva per tutto l'anno scolastico.
Supporto tecnico per chi integra: supporto@didattiko.it, indicando l'instance o l'Request-Id della richiesta. Per le prove si usa un'applicazione creata su un'installazione dimostrativa con dati di fantasia.
Progettata seguendo le Linee guida AgID sull'interoperabilità tecnica delle Pubbliche Amministrazioni (Modello di interoperabilità) e le Raccomandazioni di implementazione (Allegato 4): descrizione OpenAPI, versione nell'indirizzo, percorsi in kebab-case, Problem JSON, X-RateLimit e Retry-After, date RFC 3339, nessuna cache, stato del servizio in /status, registro delle chiamate.