Aller au contenu

API clients

Créez une clé API, consultez vos sondes et importez leurs relevés dans votre logiciel.

Écrit par l’équipe Marinade
7 min de lecture

L’API clients permet de consulter les sites, les sondes et leurs mesures en lecture seule.

Télécharger le contrat OpenAPI

Racine de l’API : https://app.marinade.pro/api/customer/v1

Première requête

  1. Dans votre compte, ouvrez Réglages, puis la section Développeurs en bas de page.
  2. Créez une clé pour votre intégration et copiez-la. Sa valeur n’est affichée qu’une seule fois.
  3. Définissez MARINADE_API_BASE_URL avec l’URL racine indiquée ci-dessus.
  4. Stockez la clé dans la variable d’environnement MARINADE_API_KEY, puis exécutez la commande suivante depuis votre serveur.
curl --fail-with-body \
  --header "Authorization: Bearer ${MARINADE_API_KEY}" \
  "${MARINADE_API_BASE_URL}/sensors?limit=100"

Authentification

Passez la clé dans l’en-tête Authorization: Bearer ${MARINADE_API_KEY} de chaque requête. Les cookies de session et les jetons de l’application mobile ne sont pas acceptés.

Utilisez HTTPS pour tous les appels. Conservez la clé côté serveur, dans une variable d’environnement ou un gestionnaire de secrets. Ne l’incluez pas dans une URL, dans le code source ou dans du code exécuté par le navigateur.

Clés API

Chaque clé donne accès à tous les sites du compte, en lecture seule. Les clés sont sans date d’expiration. Un compte peut avoir jusqu’à 10 clés non révoquées ; les clés suspendues comptent dans cette limite.

Les administrateurs et les opérateurs en mode assistance peuvent créer et révoquer des clés dans les réglages du compte. Si le compte est en lecture seule, les clés existantes restent utilisables et peuvent être révoquées, mais aucune nouvelle clé ne peut être créée.

Conditions d’accès

L’installation du compte doit être terminée et l’accès à l’application ouvert. Sinon, l’API renvoie 403 customer_access_denied.

Une clé reste liée à l’utilisateur qui l’a créée :

  • L’administrateur doit rester actif, conserver son accès au compte et son rôle d’administrateur.
  • L’opérateur doit conserver l’accès au compte.

Si ces conditions ne sont plus remplies, la clé est suspendue et l’API renvoie 401 unauthorized.

Rotation d’une clé

La révocation est immédiate. Pour remplacer une clé sans interrompre l’intégration :

  1. Créez une nouvelle clé.
  2. Remplacez la clé dans la configuration de votre intégration et vérifiez qu’un appel à l’API réussit.
  3. Révoquez l’ancienne clé.

Endpoints

Les chemins sont relatifs à MARINADE_API_BASE_URL. L’API accepte les méthodes GET et HEAD.

GET /sites

Liste des sites : id (UUID), name.

GET /sensors

Liste des sondes non supprimées et de leur dernière mesure valide. Filtres optionnels : site_id et status.

GET /sensors/{id}

Détail d’une sonde. Les sondes désactivées restent visibles ; les sondes supprimées renvoient 404.

GET /sensors/{id}/readings

Mesures individuelles, sans moyenne ni interpolation. Paramètres obligatoires : from et to, dates RFC 3339 avec fuseau. Exemple : 2026-11-01T00:00:00Z. La borne de début est incluse, celle de fin exclue. Aucune limite de durée ; la fin ne peut pas être dans le futur.

Toutes les listes acceptent limit (100 par défaut, de 1 à 1000) et cursor. Copiez pagination.next_cursor pour la suite, en conservant vos filtres et votre limite. Le curseur expire après 24 heures. has_more: false et next_cursor: null indiquent la dernière page. Aucun total n’est calculé.

Le détail renvoie data: {…}, les listes data: […]. Chaque réponse contient meta.api_version et meta.generated_at. Les listes ajoutent pagination. Ignorez les champs inconnus pour permettre l’évolution de l’API.

Comprendre les données

Une sonde contient id, name, site_id, status, last_seen_at, disabled, alerts_enabled, min_temperature_c, max_temperature_c et latest_reading. Les seuils sont les réglages actuels, pas ceux de chaque ancienne mesure.

États : pending (en attente), ok, temperature_high, temperature_low, battery_low, offline ou disabled. Un dépassement de seuil n’indique pas nécessairement qu’une alerte a déjà été déclenchée. Prévoyez un affichage de secours pour un nouvel état.

Une mesure contient id, timestamp (acquisition), received_at (réception), site_id (site enregistré à l’acquisition), temperature_c, battery_v et temperature_valid.

Les identifiants sont des chaînes opaques. Les dates renvoyées sont en UTC ; les températures en °C et les tensions en volts, sous forme de nombres JSON. null signifie indisponible. La tension n’est pas un pourcentage de pile. Les relevés historiques peuvent ne contenir aucune tension.

temperature_valid indique une température non nulle entre -40 et 80 °C inclus. L’historique conserve aussi les mesures invalides ; la dernière mesure de la sonde est la plus récente valide par date d’acquisition. latest_reading peut être nul, et une ancienne température ne prouve pas que la sonde communique encore : vérifiez last_seen_at et status.

Comparez timestamp et received_at pour connaître le délai entre la mesure et sa réception. Une réception inconnue reste nulle. L’historique décrit les relevés de cet appareil pour ce client, pas nécessairement une présence continue dans le même réfrigérateur. Utilisez le site de chaque relevé ; un remplacement ou une réaffectation peut changer l’identifiant de sonde.

Exemple de réponse

{
  "data": [
    {
      "id": "42",
      "name": "Cold room",
      "site_id": null,
      "status": "ok",
      "last_seen_at": "2026-11-02T10:01:00.000000Z",
      "disabled": false,
      "alerts_enabled": true,
      "min_temperature_c": 0.0,
      "max_temperature_c": 8.0,
      "latest_reading": {
        "id": "90715",
        "timestamp": "2026-11-02T10:00:00.000000Z",
        "received_at": "2026-11-02T10:01:00.000000Z",
        "site_id": null,
        "temperature_c": 3.6,
        "battery_v": 3.1,
        "temperature_valid": true
      }
    }
  ],
  "meta": {
    "api_version": "v1",
    "generated_at": "2026-11-02T10:02:00.000000Z"
  },
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}

Historique et données tardives

Pour afficher l’état du parc, une requête sur /sensors par minute suffit généralement. Pour importer l’historique, parcourez toutes les pages de fenêtres fixes de la durée de votre choix et enregistrez les relevés en mettant à jour les identifiants déjà connus.

Après une coupure, une sonde peut envoyer des mesures anciennes. Une retransmission peut aussi enrichir une mesure existante. La pagination ne fige pas la base : une insertion tardive peut se situer avant votre curseur. Ni la date de mesure ni un identifiant croissant ne garantissent une synchronisation complète.

Relisez régulièrement une période de recouvrement, par exemple les dernières 48 heures, et réconciliez les périodes plus anciennes après une récupération. Un recouvrement fixe ne garantit pas de capter toutes les données tardives. Si le curseur expire, recommencez la fenêtre et dédupliquez par identifiant. Les exports sont limités aux données effectivement conservées.

Exemples d’import paginé

Exemples avec une fenêtre passée fixe. Enregistrez chaque mesure par son id. Relancez l’import pour réconcilier les données tardives.

Définissez aussi MARINADE_SENSOR_ID avec l’identifiant obtenu dans la liste des sondes. Adaptez les dates from et to à la période souhaitée.

Python (bibliothèque standard)

import json
import os
import urllib.parse
import urllib.request

base = os.environ["MARINADE_API_BASE_URL"].rstrip("/")
key = os.environ["MARINADE_API_KEY"]
sensor_id = urllib.parse.quote(os.environ["MARINADE_SENSOR_ID"], safe="")
params = {"from": "2026-11-01T00:00:00Z", "to": "2026-11-02T00:00:00Z", "limit": 100}

while True:
    url = f"{base}/sensors/{sensor_id}/readings?{urllib.parse.urlencode(params)}"
    request = urllib.request.Request(url, headers={"Authorization": f"Bearer {key}"})
    with urllib.request.urlopen(request, timeout=15) as response:
        page = json.load(response)
    for reading in page["data"]:
        print(json.dumps(reading))  # Upsert into your database by reading ID.
    if not page["pagination"]["has_more"]:
        break
    params["cursor"] = page["pagination"]["next_cursor"]

Node.js

const base = process.env.MARINADE_API_BASE_URL.replace(/\/$/, "")
const key = process.env.MARINADE_API_KEY
const sensorId = encodeURIComponent(process.env.MARINADE_SENSOR_ID)
const params = new URLSearchParams({ from: "2026-11-01T00:00:00Z", to: "2026-11-02T00:00:00Z", limit: "100" })

while (true) {
  const response = await fetch(`${base}/sensors/${sensorId}/readings?${params}`, {
    headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(15000)
  })
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`)
  const page = await response.json()
  for (const reading of page.data) console.log(reading) // Upsert by reading ID.
  if (!page.pagination.has_more) break
  params.set("cursor", page.pagination.next_cursor)
}

Erreurs, limites et assistance

60 requêtes par minute par clé et 300 par compte, toutes clés confondues. Les en-têtes RateLimit-Limit, RateLimit-Remaining et RateLimit-Reset décrivent le quota de la clé ; le quota du compte peut bloquer plus tôt. RateLimit-Reset est une date Unix en secondes.

  • 400 invalid_parameter : paramètre ou curseur invalide ; cursor_expired : recommencez la fenêtre.

  • 401 unauthorized : clé absente, invalide, révoquée ou créateur non autorisé.

  • 403 customer_access_denied : accès au compte indisponible ou installation incomplète.

  • 404 not_found : ressource indisponible ou introuvable.

  • 405 method_not_allowed : utilisez GET ou HEAD.

  • 429 rate_limit_exceeded : attendez le nombre de secondes de Retry-After.

  • 503 temporarily_unavailable ou autre 5xx : réessayez avec un délai croissant et une petite variation aléatoire.

{"error":{"code":"invalid_parameter","message":"Unknown status","request_id":"example-id"}}

Ne réessayez pas indéfiniment une erreur 401. Pour toute demande d’assistance, communiquez l’en-tête X-Request-Id, jamais votre clé. Les exemples lèvent une erreur HTTP ; ajoutez une stratégie de reprise adaptée à votre logiciel.

Version v1 : première version de l’API clients. Les changements incompatibles nécessiteront une nouvelle version et une annonce avant retrait. Aucun webhook ni accès en écriture n’est disponible.

Une question qui reste sans réponse ?

Notre équipe est là pour vous donner un coup de main.