Inbound : Programme de soutirage

Endpoint inbound (opérateur de marché → SmartWatt). L'opérateur POST son programme de soutirage quotidien pour un ou plusieurs sites SmartWatt.

Cette version est le contrat qui fait foi.

Version courante du contrat : v0.2

Direction Opérateur de marché → SmartWatt. Vous transmettez chaque jour un programme de soutirage J+1 par site, à la maille 15 minutes en kWh.

Endpoint

POST /api/v0.5/energy-programs/programme-soutirage
Host: api.smartwatt.fr
Authorization: Bearer <INBOUND_TOKEN>
Content-Type: application/json

Le payload est l’enveloppe Programme_Soutirage (1 ou plusieurs sites, créneaux 15 min en kWh). Une instruction est persistée par site listé dans sites[].

Idempotence : envoyer deux fois le même couple (target_date, emitted_at, site_id) produit le même instruction_id côté SmartWatt et écrase l’instruction précédente.

Cadence d’envoi

Quotidien à J 12:30 Europe/Paris pour la journée J+1.

Authentification

Cert client mTLS + token Bearer scopé inbound:programme-soutirage, les deux obligatoires. Le token vous est fourni par SmartWatt. Voir Authentification pour le détail (cert client, rotation).

Un token sans le scope inbound:programme-soutirage reçoit 403 SCOPE_DENIED.

Format du payload

Une enveloppe contenant 1 ou plusieurs sites, chacun avec sa série de créneaux 15 minutes en kWh :

{
  "schema_version": "v0.2",
  "type": "programme_soutirage",
  "emitted_by": "OperateurDeMarche",
  "emitted_at": "2026-05-04T10:10:08Z",
  "target_date": "2026-05-05",
  "slot_duration_secs": 900,
  "sites": [
    {
      "site_id": "PRM12345678901234",
      "site_name": "SiteDemo",
      "energie_programmee": [
        {
          "debut_utc": "2026-05-04T22:00:00Z",
          "fin_utc": "2026-05-04T22:15:00Z",
          "energie_kwh": 0
        },
        {
          "debut_utc": "2026-05-04T22:45:00Z",
          "fin_utc": "2026-05-04T23:00:00Z",
          "energie_kwh": 20
        },
        {
          "debut_utc": "2026-05-04T23:00:00Z",
          "fin_utc": "2026-05-04T23:15:00Z",
          "energie_kwh": 45
        }
      ]
    }
  ]
}

Champs

ChampTypeObligatoireDescription
schema_versionstringouiVersion du schéma payload. Une seule valeur est acceptée : celle affichée en haut de page.
typestringouiToujours "programme_soutirage".
emitted_bystringnonIdentifiant de l’émetteur, repris tel quel dans l’audit.
emitted_atISO 8601 UTCouiHorodatage d’émission du fichier. Sert à dériver l’instruction_id.
target_dateYYYY-MM-DDouiJour cible (J+1 par convention).
slot_duration_secsintouiDurée d’un créneau. Standard : 900 (15 min). Doit être strictement positif.
sites[].site_idstringouiPRM Enedis : PRM + 14 chiffres (ex PRM12345678901234). Doit exister côté SmartWatt.
sites[].site_namestringnonLibellé lisible du site. Informatif, sans effet sur le traitement.
sites[].energie_programmee[]arrayouiListe contiguë d’au moins un créneau. energie_kwh = 0 = effacement.

schema_version : valeur exacte exigée

La validation compare schema_version à la version en vigueur par égalité stricte. Un champ absent est refusé (is required), et une valeur périmée ou mal formée l’est aussi : "0.2" sans le préfixe v échoue au même titre qu’une version antérieure. Les deux cas renvoient un 400 INVALID_PROGRAMME_SOUTIRAGE_REQUEST dont les details portent le motif sur la clé schema_version.

Conséquence à anticiper : lors d’une montée de version du contrat, la nouvelle valeur devient la seule acceptée. Surveillez le sélecteur en haut de page et la communication de mise en service.

Sémantique

  • energie_kwh > 0 = consommation cible (surconsommation).
  • energie_kwh = 0 = effacement (pas de charge sur ce créneau).
  • Créneau absent = pas de contrainte.
  • Créneaux 15 min alignés sur HH:00, HH:15, HH:30, HH:45.
  • Référentiel temporel : ISO 8601 UTC, suffixe Z.

Conversion énergie → puissance

SmartWatt convertit côté SmartWatt :

power_kw = energie_kwh / (slot_duration_secs / 3600)

Pour des créneaux 15 min : power_kw = energie_kwh × 4. SmartWatt applique cette puissance comme plancher sur le créneau : la consigne doit être atteinte au minimum, l’overshoot n’est pas crédité.

Réponse

Succès : 202 Accepted

{
  "status": "received",
  "count": 1,
  "instructions": [
    {
      "instruction_id": "ProgrammeSoutirage-2026-05-05-rev-20260504T101008Z-PRM12345678901234",
      "site_id": "PRM12345678901234",
      "periods_count": 96
    }
  ],
  "message": "instructions persisted, will be applied at next solver cycle"
}

L’instruction_id est dérivé côté SmartWatt, l’expéditeur ne le fournit pas. Il se termine toujours par le site_id de l’instruction, y compris pour un envoi mono-site : deux envois pour deux sites dans la même seconde reçoivent deux identifiants distincts.

Erreurs

Codeerror.codeCas typiques
400INVALID_PROGRAMME_SOUTIRAGE_REQUESTschema_version manquant ou périmé, type ≠ programme_soutirage, target_date mal formé, créneaux non contigus, énergie négative, alignement slot incorrect
400UNKNOWN_FIELDle payload porte un champ que le contrat en vigueur ne prévoit pas. Aucun champ hors contrat n’est toléré, y compris un champ d’une version ultérieure
400INVALID_DATETIMEhorodatage non parsable (emitted_at, debut_utc, fin_utc)
400INVALID_JSON_TYPEchamp présent mais du mauvais type JSON (chaîne là où un nombre est attendu, etc.)
400INVALID_JSONcorps illisible, ou plusieurs valeurs JSON à la suite dans un même corps
400SITE_NOT_FOUNDun site_id du payload n’existe pas côté SmartWatt. Cas le plus fréquent au premier envoi : vérifiez le PRM auprès de votre contact SmartWatt
401header Authorization: Bearer absent ou token invalide / expiré / révoqué
403SCOPE_DENIED ou MTLS_REQUIREDscope inbound:programme-soutirage absent, cert client mTLS absent, ou subject ne matche pas
500DB_ERRORerreur de persistance côté SmartWatt. Rejouez l’envoi ; si l’erreur persiste, signalez-la
500NO_INTEGRATOR_CTXcontexte d’intégrateur absent : anomalie de configuration côté SmartWatt, à signaler (rien à corriger dans votre payload)
503NO_STOREbase de données indisponible (transitoire, retry après quelques secondes)

Seul INVALID_PROGRAMME_SOUTIRAGE_REQUEST renseigne error.details champ par champ. Les erreurs de décodage (UNKNOWN_FIELD, INVALID_DATETIME, INVALID_JSON_TYPE) surviennent avant la validation métier : elles s’arrêtent au premier problème rencontré et reportent le message du décodeur, sans liste exhaustive des champs en faute.

Le détail des champs en faute est renvoyé dans error.details (chemin JSON pointer → message) :

{
  "error": {
    "code": "INVALID_PROGRAMME_SOUTIRAGE_REQUEST",
    "message": "ProgrammeSoutirage request validation failed",
    "details": {
      "sites[0].energie_programmee[3].debut_utc": "must be aligned to 900s boundary"
    }
  }
}

Exemple curl

curl -X POST https://api.smartwatt.fr/api/v0.5/energy-programs/programme-soutirage \
  --cert /path/to/bsp-client.crt \
  --key  /path/to/bsp-client.key \
  -H "Authorization: Bearer $INBOUND_TOKEN" \
  -H "Content-Type: application/json" \
  -d @Programme_Soutirage_2026-05-05.json