Aller au contenu principal
République du Burundi PNISAN Guide d'utilisation

Référence

Interface de programmation

Transmettre des valeurs par l'API entrante /api/v1 (clés, signature HMAC, points d'accès, erreurs) et réutiliser les données ouvertes publiques (CSV, graphiques intégrables).

La PNISAN offre deux voies d'échange automatisé. L'API entrante permet à un système sectoriel (santé, agriculture, hydraulique, éducation, protection sociale) de transmettre des valeurs d'indicateurs sans passer par un fichier : chaque requête est authentifiée par une clé et signée. Les données ouvertes du portail permettent à quiconque de télécharger les valeurs validées en CSV et d'intégrer des graphiques sur un autre site, sans compte. Cette page décrit les deux.

API entrante : principes #

  • Adresse de base : https://pnisan.bi/api/v1. Échanges en JSON, encodage UTF-8, messages d'erreur en français.
  • Chaque envoi entre dans la zone de transit (canal API entrante), puis suit exactement le circuit de l'import de fichier : normalisation, contrôles qualité, arbitrage des sources, validation provinciale et nationale.
  • Les valeurs entrent au statut « Soumis » : aucune n'est publiée sans validation humaine. Une valeur déjà validée n'est jamais remplacée par l'API ; l'écriture est consignée comme conflit et attend la décision d'un administrateur.
  • L'effectif est facultatif par cette voie : une valeur sans effectif est acceptée et signalée en avertissement.

Obtenir une clé #

Les clés sont émises dans la console, écran Clés d'accès applicatif, par un super-administrateur ou un administrateur national.

Champ Rôle
Organisation Système ou institution émettrice
Identifiant Public, de la forme pnin_ suivi de 24 caractères, à transmettre dans l'en-tête X-Cle
Secret 48 caractères, affiché une seule fois à l'émission : « Copiez ce secret maintenant et transmettez-le au système émetteur par un canal sûr. Il ne sera plus jamais affiché. »
Indicateurs autorisés Codes d'indicateurs ; vide : tout le référentiel
Territoires autorisés Codes de provinces ou de communes, ou national ; une province couvre ses communes ; vide : tout le territoire
Requêtes par minute Plafond de la clé, 60 par défaut
Expire le Date d'expiration facultative

Un secret perdu ne se récupère pas : l'administrateur émet une nouvelle clé et révoque l'ancienne (bouton Révoquer, action définitive). Émission, modification, révocation et chaque envoi reçu sont consignés au Journal d'audit.

Liste des clés d'accès applicatif
Liste des clés d'accès applicatif

Signer une requête #

Trois en-têtes sont obligatoires sur chaque requête :

En-tête Contenu
X-Cle Identifiant de la clé
X-Horodatage Instant de la requête, en secondes depuis le 1er janvier 1970 UTC
X-Signature HMAC-SHA256 en hexadécimal minuscule de la chaîne à signer, avec le secret pour clé

La chaîne à signer compte quatre lignes séparées par un saut de ligne, sans saut de ligne final :

METHODE
CHEMIN
HORODATAGE
EMPREINTE_DU_CORPS
  • METHODE : GET ou POST, en majuscules ;
  • CHEMIN : chemin tel qu'envoyé, paramètres compris, par exemple /api/v1/valeurs ;
  • HORODATAGE : la valeur exacte de X-Horodatage ;
  • EMPREINTE_DU_CORPS : SHA-256 hexadécimal du corps brut ; pour un GET sans corps, empreinte de la chaîne vide (e3b0c442...b855).

Le corps signé doit être exactement celui qui est envoyé : sérialisez le JSON une seule fois, signez ces octets, envoyez ces octets. L'horodatage doit être à moins de cinq minutes de l'horloge du serveur (synchronisez l'émetteur par NTP), et une même signature ne sert qu'une fois : pour renvoyer un lot, signez-le de nouveau avec un nouvel horodatage.

Points d'accès #

Méthode et adresse Usage
POST /api/v1/valeurs Déposer un lot de 500 valeurs au plus
GET /api/v1/ingestions/{id} Suivre un envoi : statut, compteurs, erreurs, avertissements, conflits, répartition des valeurs par statut de validation. Une clé ne voit que ses propres envois
GET /api/v1/referentiel Indicateurs du périmètre de la clé : code, intitulé, système, unité, périodicité, désagrégations, statut
GET /api/v1/territoires Provinces et communes du périmètre (codes, P-codes, codes ISIBU, découpage), et admission des valeurs nationales (code BDI)

Champs d'une valeur #

Champ Obligatoire Contenu
indicateur Oui Code du référentiel, par exemple NUT-01
code_territoire ou territoire Non Code (P-code, code d'ancienne province, code ISIBU) ou nom ; absent : valeur nationale
periode_debut Oui AAAA-MM-JJ, JJ/MM/AAAA, AAAA-MM ou AAAA
periode_fin Non Même format ; absente : fin du mois de début
periode Non Libellé affiché, par exemple 2022-2023
valeur Oui Nombre, point ou virgule décimale
effectif Non Entier
desagregation, unite Non Clé de désagrégation ; unité déclarée, confrontée au référentiel
source_donnee, note_source, source_url Non Publication d'origine, note, lien http ou https complet

Le lot peut porter un libelle et une reference (255 caractères chacun). La réponse 201 renvoie l'ingestion créée avec ses erreurs ligne par ligne : une ligne en erreur n'empêche pas les autres de passer. Un lot identique déjà reçu avec la même clé n'est pas retraité : réponse 200 avec "deja_recu": true.

Exemple de requête #

CLE="pnin_xxxxxxxxxxxxxxxxxxxxxxxx"
SECRET="..."
CHEMIN="/api/v1/valeurs"
CORPS='{"libelle":"Suivi nutritionnel, janvier 2026","valeurs":[{"indicateur":"NUT-01","code_territoire":"BI-GI","periode_debut":"2026-01-01","periode_fin":"2026-01-31","valeur":42.5,"effectif":1200}]}'
HORODATAGE=$(date +%s)
EMPREINTE=$(printf '%s' "$CORPS" | openssl dgst -sha256 -r | cut -d' ' -f1)
SIGNATURE=$(printf 'POST\n%s\n%s\n%s' "$CHEMIN" "$HORODATAGE" "$EMPREINTE" \
  | openssl dgst -sha256 -hmac "$SECRET" -r | cut -d' ' -f1)

curl -sS -X POST "https://pnisan.bi$CHEMIN" \
  -H "Content-Type: application/json" \
  -H "X-Cle: $CLE" -H "X-Horodatage: $HORODATAGE" -H "X-Signature: $SIGNATURE" \
  --data-binary "$CORPS"

Utilisez --data-binary et non -d, qui modifierait le corps signé. Réponse type :

{
  "message": "Envoi reçu : 1 valeur(s) en attente de validation, 0 ligne(s) en erreur, 0 conflit(s).",
  "deja_recu": false,
  "ingestion": { "id": 42, "statut": "en_validation", "lignes_total": 1, "lignes_valides": 1, "score_qualite": 100 }
}

En Python, la signature s'écrit :

corps = json.dumps(charge, ensure_ascii=False).encode("utf-8")
horodatage = str(int(time.time()))
chaine = "\n".join(["POST", "/api/v1/valeurs", horodatage, hashlib.sha256(corps).hexdigest()])
signature = hmac.new(SECRET.encode(), chaine.encode(), hashlib.sha256).hexdigest()

Codes d'erreur #

Les erreurs ont la forme {"erreur": {"code": "...", "message": "..."}} : le code est stable, destiné au programme ; le message s'adresse à l'exploitant.

Statut Codes Cause fréquente
400 json_invalide, requete_invalide Corps qui n'est pas un JSON valide
401 entetes_absents, cle_inconnue, cle_revoquee, cle_expiree, horodatage_invalide, horodatage_hors_fenetre, signature_invalide Horloge décalée, secret erroné, corps modifié après signature
404 ressource_introuvable Ingestion d'une autre clé
405 methode_non_autorisee Méthode incorrecte
409 requete_rejouee Signature déjà utilisée : signez de nouveau
422 valeurs_absentes, trop_de_lignes, libelle_invalide, reference_invalide Lot vide ou de plus de 500 valeurs
429 trop_de_requetes Plafond de la clé atteint ; respectez l'en-tête Retry-After
500 erreur_interne L'envoi n'est pas enregistré, vous pouvez le renouveler

Les envois reçus se consultent dans la console, écran Ingestion des données, canal API entrante. La spécification OpenAPI 3 complète est tenue par l'équipe technique (docs/openapi.yaml).

Données ouvertes du portail #

Sans compte ni clé, le portail publie les valeurs validées au niveau national, au-dessus du seuil de masquage :

Adresse Contenu
https://pnisan.bi/indicateurs.csv Catalogue : une ligne par indicateur avec la dernière valeur nationale, sa période, son statut, son évolution, sa source, le lien de la source, la date de validation et l'adresse de la fiche. Filtres recherche, systeme (par exemple ?systeme=nutrition) et periodicite
https://pnisan.bi/indicateurs/{id}/donnees.csv Série d'un indicateur : valeurs nationales et provinciales, période, désagrégation, unité, statut, source, lien de la source, date de validation
https://pnisan.bi/prix-des-denrees/donnees.csv Relevés de prix des denrées, un relevé par ligne, avec marché, P-code, coordonnées, éditeur, licence, adresse source et copie archivée ; filtre ?denree=
https://pnisan.bi/integrer/indicateurs/{id} Graphique d'un indicateur à intégrer dans une page (balise iframe)
https://pnisan.bi/integrer/carte Carte du Tableau de bord à intégrer

Les fichiers CSV sont encodés en UTF-8 avec marque d'ordre des octets, séparés par des points-virgules, avec la virgule comme séparateur décimal. Le numéro {id} d'un indicateur figure dans l'adresse de sa Fiche indicateur.

Pour aller plus loin #