Skip to content

Api rest Open3Cl

Michael Desigaud edited this page Nov 13, 2026 · 3 revisions

API REST Open3CL

RedFroggy héberge le moteur Open3CL sous forme d'API REST. Vous envoyez un DPE, l'API le recalcule et vous le renvoie complété des résultats : consommations, émissions, étiquettes.

Obtenir une clé d'API

L'API est privée : sans clé valide, chaque appel est rejeté avec une erreur 403.

Pour obtenir une clé, écrivez à contact@redfroggy.fr en précisant votre organisation et l'usage prévu (volume approximatif, intégration serveur, etc.).

La clé est personnelle et secrète. Ne la publiez pas dans un dépôt de code et ne l'utilisez pas dans un navigateur ou une application mobile, où elle serait visible par tous. Appelez l'API depuis votre serveur.

Référence

   
URL https://3cl.redfroggy.io/
Méthode POST
Authentification en-tête X-Auth-Token: <votre clé d'API>
Corps un DPE complet, en JSON ou en XML (format ADEME)
Réponse le DPE recalculé, au même format que la requête
Délai maximal 300 s par appel

Exemple de réponse 400 :

{ "err": "DPE invalide : Cannot read properties of undefined (reading 'enum_modele_dpe_id')" }

Bonnes pratiques

  • Gardez la clé côté serveur, dans une variable d'environnement ou un gestionnaire de secrets, jamais dans le code source.
  • Prévoyez un délai d'attente long (quelques secondes en temps normal, mais le premier appel après une période d'inactivité peut être plus lent, le temps que l'API démarre).
  • Ne relancez pas en boucle un DPE en erreur 400 : le même DPE donnera la même erreur.
  • Pour des volumes importants (traitement de corpus, appels en masse), prévenez-nous à contact@redfroggy.fr avant de lancer le traitement.
  • Pour calculer sans réseau ou intégrer le moteur dans votre application, utilisez directement le paquet npm @open3cl/engine (voir le README).

API REST Open3CL

RedFroggy héberge le moteur Open3CL sous forme d'API REST. Vous envoyez un DPE, l'API le recalcule et vous le renvoie complété des résultats : consommations, émissions, étiquettes.

Obtenir une clé d'API

L'API est privée : sans clé valide, chaque appel est rejeté avec une erreur 403.

Pour obtenir une clé, écrivez à [contact@redfroggy.fr](mailto:contact@redfroggy.fr) en précisant votre organisation et l'usage prévu (volume approximatif, intégration serveur, etc.).

La clé est personnelle et secrète. Ne la publiez pas dans un dépôt de code et ne l'utilisez pas dans un navigateur ou une application mobile, où elle serait visible par tous. Appelez l'API depuis votre serveur.

Référence

URL https://3cl.redfroggy.io/
Méthode POST
Authentification en-tête X-Auth-Token: <votre clé d'API>
Corps un DPE complet, en JSON ou en XML (format ADEME)
Réponse le DPE recalculé, au même format que la requête
Délai maximal 300 s par appel

Le format de la requête est déterminé par l'en-tête Content-Type :

Content-Type de la requête Corps attendu Réponse
application/json DPE au format JSON application/json
application/xml ou text/xml DPE XML ADEME, tel que téléchargé sur l'[observatoire DPE](https://observatoire-dpe-audit.ademe.fr) application/xml

Envoyer un DPE JSON ou XML

XML : envoyez le fichier XML du DPE tel quel, sans transformation. C'est le plus simple si vous partez d'un DPE de l'observatoire ADEME.

JSON : le DPE doit suivre la structure du XML ADEME, convertie en JSON ({ "numero_dpe": …, "administratif": …, "logement": … }). Les collections sont des tableaux. Des DPE XML d'exemple sont disponibles dans [test/fixtures](https://github.com/Open3CL/engine/tree/main/test/fixtures) du dépôt Open3CL.

Le corps n'est pas validé contre un schéma : un DPE incomplet ou incohérent est rejeté par le moteur avec une erreur 400 (voir [Erreurs](#erreurs)).

Exemples de code

Dans tous les exemples, la clé d'API est lue dans la variable d'environnement OPEN3CL_API_KEY :

export OPEN3CL_API_KEY='votre-clé-d-api'

curl

DPE JSON :

curl -X POST https://3cl.redfroggy.io/ \
  -H "X-Auth-Token: $OPEN3CL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data @dpe.json \
  -o dpe-calcule.json

DPE XML :

curl -X POST https://3cl.redfroggy.io/ \
  -H "X-Auth-Token: $OPEN3CL_API_KEY" \
  -H 'Content-Type: application/xml' \
  --data-binary @dpe.xml \
  -o dpe-calcule.xml

Pour un fichier XML, utilisez --data-binary et pas --data : ce dernier supprime les retours à la ligne.

Afficher directement l'étiquette avec [jq](https://jqlang.org/) :

curl -s -X POST https://3cl.redfroggy.io/ \
  -H "X-Auth-Token: $OPEN3CL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data @dpe.json \
  | jq '.logement.sortie.ep_conso | {classe_bilan_dpe, ep_conso_5_usages_m2}'

JavaScript / Node.js

Node.js 18 ou plus récent (fetch natif), sans dépendance.

DPE JSON :

import { readFile } from 'node:fs/promises';

const dpe = JSON.parse(await readFile('dpe.json', 'utf-8'));

const response = await fetch('https://3cl.redfroggy.io/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Auth-Token': process.env.OPEN3CL_API_KEY
  },
  body: JSON.stringify(dpe)
});

if (!response.ok) {
  throw new Error(`Open3CL ${response.status} : ${await response.text()}`);
}

const result = await response.json();
const { classe_bilan_dpe, ep_conso_5_usages_m2 } = result.logement.sortie.ep_conso;
console.log(`Étiquette ${classe_bilan_dpe} (${ep_conso_5_usages_m2} kWhEP/m²/an)`);

DPE XML :

import { readFile, writeFile } from 'node:fs/promises';

const response = await fetch('https://3cl.redfroggy.io/', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/xml',
    'X-Auth-Token': process.env.OPEN3CL_API_KEY
  },
  body: await readFile('dpe.xml', 'utf-8')
});

if (!response.ok) {
  throw new Error(`Open3CL ${response.status} : ${await response.text()}`);
}

await writeFile('dpe-calcule.xml', await response.text());

Java

Java 11 ou plus récent (java.net.http.HttpClient), sans dépendance. Le fichier est envoyé tel quel, que ce soit du JSON ou du XML.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.time.Duration;

public class Open3clClient {

    private static final URI API_URL = URI.create("https://3cl.redfroggy.io/");

    private final HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .build();

    private final String apiKey = System.getenv("OPEN3CL_API_KEY");

    /** contentType : "application/json" ou "application/xml" */
    public String calculate(Path dpeFile, String contentType) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(API_URL)
                .timeout(Duration.ofMinutes(5))
                .header("Content-Type", contentType)
                .header("X-Auth-Token", apiKey)
                .POST(HttpRequest.BodyPublishers.ofFile(dpeFile))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() != 200) {
            throw new IllegalStateException("Open3CL " + response.statusCode() + " : " + response.body());
        }
        return response.body();
    }

    public static void main(String[] args) throws Exception {
        Open3clClient open3cl = new Open3clClient();
        String json = open3cl.calculate(Path.of("dpe.json"), "application/json");
        String xml = open3cl.calculate(Path.of("dpe.xml"), "application/xml");
        System.out.println(json.length() + " / " + xml.length());
    }
}

Pour lire le JSON renvoyé, utilisez la bibliothèque de votre projet (Jackson, par exemple) :

JsonNode epConso = new ObjectMapper().readTree(json).at("/logement/sortie/ep_conso");
String classe = epConso.get("classe_bilan_dpe").asText();

Python

Avec [requests](https://requests.readthedocs.io/) (pip install requests).

DPE JSON :

import json
import os

import requests

API_URL = "https://3cl.redfroggy.io/"
HEADERS = {"X-Auth-Token": os.environ["OPEN3CL_API_KEY"]}

with open("dpe.json", encoding="utf-8") as f:
    dpe = json.load(f)

response = requests.post(API_URL, json=dpe, headers=HEADERS, timeout=300)
response.raise_for_status()

ep_conso = response.json()["logement"]["sortie"]["ep_conso"]
print(f"Étiquette {ep_conso['classe_bilan_dpe']} ({ep_conso['ep_conso_5_usages_m2']} kWhEP/m²/an)")

DPE XML :

with open("dpe.xml", "rb") as f:
    response = requests.post(
        API_URL,
        data=f,
        headers={**HEADERS, "Content-Type": "application/xml"},
        timeout=300,
    )
response.raise_for_status()

with open("dpe-calcule.xml", "w", encoding="utf-8") as f:
    f.write(response.text)

PHP

Avec l'extension cURL.

<?php
function open3cl_calculate(string $file, string $contentType): string
{
    $ch = curl_init('https://3cl.redfroggy.io/');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => file_get_contents($file),
        CURLOPT_HTTPHEADER => [
            'Content-Type: ' . $contentType,
            'X-Auth-Token: ' . getenv('OPEN3CL_API_KEY'),
        ],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 300,
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($status !== 200) {
        throw new RuntimeException("Open3CL $status : $body");
    }
    return $body;
}

$result = json_decode(open3cl_calculate('dpe.json', 'application/json'), true);
echo $result['logement']['sortie']['ep_conso']['classe_bilan_dpe'], PHP_EOL;

file_put_contents('dpe-calcule.xml', open3cl_calculate('dpe.xml', 'application/xml'));

C#

.NET 6 ou plus récent.

using System.Net.Http.Headers;
using System.Text.Json;

using var http = new HttpClient { Timeout = TimeSpan.FromMinutes(5) };
http.DefaultRequestHeaders.Add("X-Auth-Token", Environment.GetEnvironmentVariable("OPEN3CL_API_KEY"));

async Task<string> CalculateAsync(string file, string contentType)
{
    var content = new StreamContent(File.OpenRead(file));
    content.Headers.ContentType = new MediaTypeHeaderValue(contentType);

    var response = await http.PostAsync("https://3cl.redfroggy.io/", content);
    var body = await response.Content.ReadAsStringAsync();
    if (!response.IsSuccessStatusCode)
        throw new HttpRequestException($"Open3CL {(int)response.StatusCode} : {body}");
    return body;
}

var json = await CalculateAsync("dpe.json", "application/json");
var classe = JsonDocument.Parse(json).RootElement
    .GetProperty("logement").GetProperty("sortie")
    .GetProperty("ep_conso").GetProperty("classe_bilan_dpe").GetString();
Console.WriteLine($"Étiquette {classe}");

await File.WriteAllTextAsync("dpe-calcule.xml", await CalculateAsync("dpe.xml", "application/xml"));

Go

Bibliothèque standard uniquement.

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func calculate(file, contentType string) ([]byte, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	req, err := http.NewRequest(http.MethodPost, "https://3cl.redfroggy.io/", f)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	req.Header.Set("X-Auth-Token", os.Getenv("OPEN3CL_API_KEY"))

	client := &http.Client{Timeout: 5 * time.Minute}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("open3cl %d : %s", resp.StatusCode, body)
	}
	return body, nil
}

func main() {
	xml, err := calculate("dpe.xml", "application/xml")
	if err != nil {
		panic(err)
	}
	os.WriteFile("dpe-calcule.xml", xml, 0o644)
}

Erreurs

Code Cause Que faire
200 DPE recalculé —
400 Corps illisible (JSON ou XML mal formé) ou DPE rejeté par le moteur (donnée obligatoire manquante, valeur incohérente…) Le message est dans le champ err de la réponse, toujours en JSON. Vérifiez le DPE envoyé.
403 En-tête X-Auth-Token absent, clé invalide ou révoquée Vérifiez la clé ; en cas de doute, écrivez à [contact@redfroggy.fr](mailto:contact@redfroggy.fr).
404 URL autre que https://3cl.redfroggy.io/ Appelez la racine /, sans chemin.
405 Méthode autre que POST Utilisez POST.

Exemple de réponse 400 :

{ "err": "DPE invalide : Cannot read properties of undefined (reading 'enum_modele_dpe_id')" }

Bonnes pratiques

  • Gardez la clé côté serveur, dans une variable d'environnement ou un gestionnaire de secrets, jamais dans le code source.
  • Prévoyez un délai d'attente long (quelques secondes en temps normal, mais le premier appel après une période d'inactivité peut être plus lent, le temps que l'API démarre).
  • Ne relancez pas en boucle un DPE en erreur 400 : le même DPE donnera la même erreur.
  • Pour des volumes importants (traitement de corpus, appels en masse), prévenez-nous à [contact@redfroggy.fr](mailto:contact@redfroggy.fr) avant de lancer le traitement.
  • Pour calculer sans réseau ou intégrer le moteur dans votre application, utilisez directement le paquet npm [@open3cl/engine](https://www.npmjs.com/package/@open3cl/engine) (voir le [README](https://github.com/Open3CL/engine#readme)).