Panoramica

NIS2 Agile espone due famiglie di API: Services API per lettura dati di compliance in tempo reale, e Webhook API per notifiche push su eventi NIS2.

Base URL: https://nis2.agile.software/api
Rate Limiting: Services API: 100 richieste/ora per API Key. Webhook delivery: max 1000/ora per subscription.
Formato risposta: Tutte le risposte sono JSON con envelope { "success": bool, "data": {}, "message": "..." }

Autenticazione

Le Services API usano API Keys con scope granulari. Le API di gestione (webhook, key management) usano JWT Bearer token della sessione utente.

API Key — 3 modalità

# Header (raccomandato)
X-API-Key: nis2_abc123def456...

# Authorization Bearer
Authorization: Bearer nis2_abc123def456...

# Query string (sconsigliato in prod)
GET /api/services/risks-feed?api_key=nis2_abc123def456...

JWT Bearer — Per gestione API

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Scope disponibili

read:all
Accesso completo in lettura a tutti i dati
read:compliance
Compliance score e controlli Art.21
read:risks
Risk register e matrice rischi ISO 27005
read:incidents
Incidenti e timeline Art.23
read:assets
Inventario asset critici
read:supply_chain
Supply chain e rischio fornitori
read:policies
Policy approvate

Header obbligatorio

X-Organization-Id: 42   # ID organizzazione target

Gestione Errori

HTTPerror_codeDescrizione
400VALIDATION_ERRORParametri obbligatori mancanti o non validi
401UNAUTHORIZEDAPI Key assente, scaduta o non valida
403INSUFFICIENT_SCOPEScope insufficiente per questa risorsa
404NOT_FOUNDRisorsa non trovata
429RATE_LIMITEDLimite richieste superato
500INTERNAL_ERRORErrore interno del server
{
  "success": false,
  "message": "Scope insufficiente: richiesto read:risks",
  "error_code": "INSUFFICIENT_SCOPE"
}

Services API

Endpoint GET per leggere dati di compliance da sistemi esterni. Autenticazione tramite API Key con scope granulari.

GET /services/status Public Health check piattaforma

Stato della piattaforma, versione API e timestamp. Non richiede autenticazione.

Risposta 200

{
  "status": "ok",
  "version": "1.0.0",
  "timestamp": 1709900400,
  "platform": "NIS2 Agile"
}
GET /services/compliance-summary read:compliance

Score di conformità NIS2 aggregato per dominio Art.21, con statistiche rischi, incidenti aperti e policy approvate.

Risposta 200

{
  "overall_score": 73,
  "label": "substantially_compliant",
  "domain_scores": [
    { "category": "governance", "score": 80, "answered": 8, "total": 10 }
  ],
  "risks": { "total": 24, "critical": 2, "high": 5 },
  "incidents": { "open": 3, "significant": 1 },
  "policies": { "approved": 12, "draft": 4 }
}
GET /services/risks-feed read:risks

Feed rischi con filtri su livello, area NIS2, stato e data. Include deadline di trattamento.

Query Parameters

ParametroTipoDescrizione
levelstringFiltro livello: critical, high, medium, low
areastringCategoria rischio (es. network_security)
statusstringStato: open, in_treatment, closed
fromdatetimeFiltra da data ISO (es. 2026-01-01T00:00:00)
limitintegerMax risultati (default 50, max 200)

Risposta 200

{
  "risks": [
    {
      "id": 15,
      "risk_code": "RSK-2026-015",
      "title": "Vulnerabilità VPN senza MFA",
      "category": "network_security",
      "risk_level": "high",
      "risk_score": 15,
      "treatment": "mitigate",
      "nis2_article": "21.2.i",
      "created_at": "2026-01-15T10:30:00+01:00"
    }
  ],
  "total": 24, "filters": { "level": "high" }
}
GET /services/incidents-feed read:incidents

Feed incidenti con status Art.23 (deadlines 24h/72h/30d) e flag di scadenza. Utile per integrare in SIEM e SOC dashboard.

Query Parameters

ParametroTipoDescrizione
statusstringopen, investigating, resolved, closed
severitystringcritical, high, medium, low
significant_onlybooleanSolo incidenti Art.23 significativi
fromdatetimeFiltra da data ISO

Risposta 200 — Elemento

{
  "id": 7,
  "incident_code": "INC-2026-007",
  "title": "Accesso non autorizzato sistema ERP",
  "severity": "high",
  "is_significant": true,
  "art23_status": {
    "early_warning": { "due": "2026-02-21T14:00:00+01:00", "sent": true, "overdue": false },
    "notification": { "due": "2026-02-23T14:00:00+01:00", "sent": false, "overdue": false },
    "final_report": { "due": "2026-03-22T14:00:00+01:00", "sent": false, "overdue": false }
  }
}
GET /services/controls-status read:compliance

Stato dei controlli di sicurezza Art.21 raggruppati per categoria (governance, network_security, access_control, ecc.).

Risposta 200 — Elemento categoria

{
  "category": "network_security",
  "total": 8,
  "implemented": 5,
  "partial": 2,
  "not_implemented": 1,
  "score": 75
}
GET /services/assets-critical read:assets

Inventario asset critici con tipo, livello di criticità e dipendenze. Filtrabili per tipo e livello.

Query Parameters

ParametroTipoDescrizione
typestringserver, network, software, data, service
criticalitystringcritical, high, medium, low
GET /services/suppliers-risk read:supply_chain

Panoramica rischio fornitori con risk_score, data ultima valutazione e flag critici. Include stats aggregate.

Risposta 200 — Stats

{
  "suppliers": [...],
  "stats": {
    "total": 18,
    "critical": 2,
    "high": 4,
    "avg_risk_score": 42
  }
}
GET /services/policies-approved read:policies

Policy approvate con categoria, articolo NIS2 di riferimento e versione. Opzionalmente include il testo completo.

Query Parameters

ParametroTipoDescrizione
categorystringFiltra per categoria (es. incident_response)
include_contentbooleanInclude testo policy (default: false)

Gestione API Keys

CRUD API Keys. Richiede autenticazione JWT con ruolo org_admin.

GET /webhooks/api-keys JWT Lista API Keys dell'organizzazione

Restituisce tutte le API Keys (attive e revocate) dell'organizzazione corrente. Non espone mai il testo completo della chiave.

POST /webhooks/api-keys JWT org_admin
La chiave completa viene restituita SOLO UNA VOLTA nella risposta di creazione. Salvarla immediatamente.

Body (JSON)

CampoTipoObbligatorioDescrizione
namestring*Nome descrittivo (es. "SIEM Integration")
scopesarray*Array di scope (es. ["read:risks","read:incidents"])
expires_atdatetimeScadenza opzionale (ISO 8601)

Risposta 201

{
  "id": 5,
  "name": "SIEM Integration",
  "key": "nis2_a3f8c2d1e4b7...",
  "key_prefix": "nis2_a3f8c2",
  "scopes": ["read:risks", "read:incidents"],
  "warning": "Salva questa chiave in modo sicuro. Non sara' piu' visibile."
}
DELETE /webhooks/api-keys/{id} JWT org_admin Revoca (soft delete) API Key

Revoca una API Key impostando is_active = 0. La chiave non viene eliminata dal DB per mantenere l'audit trail.

Webhook Subscriptions

Gestione sottoscrizioni webhook outbound. NIS2 Agile invierà POST HTTP all'URL configurato al verificarsi degli eventi sottoscritti.

GET /webhooks/subscriptions JWT Lista subscriptions + statistiche delivery

Include statistiche di delivery (total, success, failed) per ogni subscription. Non espone il secret HMAC.

POST /webhooks/subscriptions JWT org_admin
Il secret HMAC viene restituito SOLO UNA VOLTA. Usarlo per verificare la firma X-NIS2-Signature.

Body (JSON)

CampoTipoObbligatorioDescrizione
namestring*Nome descrittivo
urlstring*URL https:// destinazione POST
eventsarray*Array eventi (o ["*"] per wildcard)

Risposta 201

{
  "id": 3,
  "secret": "a3f8c2d1e4b7f9a2c8d3e1f4...",
  "warning": "Salva il secret. Sara' usato per verificare la firma X-NIS2-Signature."
}
PUT /webhooks/subscriptions/{id} JWT Aggiorna name, events, is_active

Aggiornamento parziale (PATCH semantics). Solo i campi inviati vengono aggiornati: name, events, is_active.

DELETE /webhooks/subscriptions/{id} JWT org_admin Elimina subscription e storico delivery
POST /webhooks/subscriptions/{id}/test JWT Invia evento webhook.test

Invia un ping di test per verificare che l'endpoint remoto sia raggiungibile e risponda correttamente. Controlla il delivery log per il risultato.

GET /webhooks/deliveries JWT Log ultimi 100 delivery

Query Parameters

ParametroTipoDescrizione
subscription_idintegerFiltra per subscription specifica

Catalogo Eventi Webhook

NIS2 Agile emette eventi su tutte le operazioni rilevanti per la compliance. Ogni evento ha un payload tipizzato.

EventoTriggerPayload
incident.createdNuovo incidente registratoincidentPayload(incident, 'created')
incident.updatedIncidente modificatoincidentPayload(incident, 'updated')
incident.significantIncidente flaggato Art.23incidentPayload con deadlines
incident.deadline_warningScadenza 24h/72h imminentedeadline + ore rimanenti
risk.high_createdRischio HIGH o CRITICAL creatoriskPayload(risk, 'created')
risk.updatedRischio aggiornatoriskPayload(risk, 'updated')
compliance.score_changedVariazione score >5%previous_score, new_score, delta, label
policy.approvedPolicy approvatapolicyPayload(policy)
policy.createdNuova policy creataid, title, category, nis2_article
supplier.risk_flaggedFornitore con rischio HIGH/CRITICALsupplier + risk_level
assessment.completedGap assessment completatoscore, gap_count, top_gaps[]
whistleblowing.receivedNuova segnalazione anonimaid, category, priority (no PII)
normative.updateAggiornamento normativo NIS2/ACNtitle, source, effective_date
webhook.testPing manuale di testmessage, timestamp
*Wildcard — tutti gli eventi

Struttura envelope payload

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "incident.created",
  "api_version": "1.0.0",
  "created": 1709900400,
  "created_at": "2026-03-07T10:00:00+01:00",
  "source": "nis2-agile",
  "org_id": 42,
  "data": { "action": "created", "incident": { ... } }
}

Verifica Firma Webhook

Ogni delivery include l'header X-NIS2-Signature con firma HMAC-SHA256 del body. Verifica sempre la firma prima di processare il payload.

Pattern identico a Stripe webhook verification: sha256=HMAC_SHA256(body, secret)

Headers inviati

X-NIS2-Signature: sha256=a3f8c2d1e4b7...
X-NIS2-Event: incident.created
X-NIS2-Delivery-Id: 147
X-NIS2-Attempt: 1
Content-Type: application/json

Verifica in PHP

$body = file_get_contents('php://input');
$secret = 'il-tuo-secret';
$signature = $_SERVER['HTTP_X_NIS2_SIGNATURE'];
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

Verifica in Python

import hmac, hashlib

secret = b'il-tuo-secret'
body = request.data  # bytes
expected = 'sha256=' + hmac.new(secret, body, hashlib.sha256).hexdigest()
received = request.headers.get('X-NIS2-Signature', '')

if not hmac.compare_digest(expected, received):
    abort(401)

Retry Policy

TentativoRitardoNote
ImmediatoFire-and-forget sincrono
+5 minutiProcessato da cron
+30 minutiUltimo tentativo

Dopo 10 fallimenti consecutivi la subscription viene messa in pausa automatica (failure_count >= 10).

NIS2 Agile API Reference v1.0.0 — © 2026 CertiSource Srl — nis2.agile.software