Aller au contenu
Mon Chai Développeurs Aller sur Mon Chai

API REST v1

Lire stocks et factures avec une clé d'API personnelle et de simples requêtes HTTP — référence engendrée depuis la description OpenAPI.

L'API REST v1 lit les mêmes données que le connecteur (chaque point d'API sert le même outil, avec les mêmes contrôles), mais avec de simples requêtes GET et une clé d'API personnelle : pas de navigateur, pas d'OAuth. Elle est en lecture seule. Une clé vaut pour une personne dans une exploitation.

Connecteur MCP ou API REST : lequel choisir ?

  • API REST : un script, un tableur, un serveur, une tâche planifiée — un programme qui tourne seul. Une clé dans une variable d'environnement, un GET, du JSON.
  • Connecteur MCP : un assistant IA (Claude, ChatGPT) ou une application dont chaque utilisateur se connecte lui-même à Mon Chai, avec un écran de consentement et des jetons qui se renouvellent.

Les deux lisent la même chose ; aucun des deux n'écrit.

Créer et révoquer une clé

  1. Dans Mon Chai : Administration › Connecteur IA & clés d'API, onglet « Clés d'API (vos programmes) ». Réservé au propriétaire et aux administrateurs de l'exploitation.
  2. Donnez un nom à la clé (celui de votre programme), cochez les portées utiles, choisissez sa durée de vie (30, 90, 365 jours). Au plus 5 clés actives par personne et par exploitation.
  3. La clé s'affiche une seule fois : copiez-la tout de suite dans un gestionnaire de mots de passe ou dans la configuration de votre programme. Mon Chai n'en garde qu'une empreinte et ne pourra plus vous la montrer.

Forme d'une clé : mc_live_<préfixe : 10 caractères>_<secret : 43 caractères>. Le préfixe n'est pas secret : c'est lui que l'écran affiche pour reconnaître la clé. Pour révoquer une clé, même écran, bouton « Révoquer » : l'effet est immédiat. Une clé expirée ou révoquée ne se réactive pas ; on en crée une nouvelle.

S'authentifier

Chaque requête porte la clé dans l'en-tête Authorization, et uniquement là :

Authorization: Bearer mc_live_…

Portées et droits

PortéeCe qu'elle ouvre
stocks:lectureStocks : bouteilles, formats, cuvées, vrac
factures:lectureFactures et chiffre d'affaires : factures de vente et d'achat, impayés, chiffre d'affaires

Les deux sont exigés à chaque requête : la portée de la clé et le droit actuel de la personne dans l'exploitation. Un droit retiré coupe la clé (403) sans la révoquer ; une personne qui quitte l'exploitation perd ses clés (401).

Réponses et erreurs

Une réponse 200 est l'objet JSON de l'outil correspondant du connecteur, avec son champ etat (ok ou empty). Les montants sont des chaînes décimales ("125.50"), les dates au format AAAA-MM-JJ. Toute erreur a la même forme :

{"erreur": {"code": "portee_insuffisante", "message": "Cette clé ne permet pas de lire …"}}

Testez le code (stable) dans votre programme ; le message est une phrase en français qui dit quoi faire. details s'ajoute parfois (paramètres acceptés, candidats).

StatutCodesCause, et quoi faire
400cle_dans_l_adresse, parametre_inconnu, parametre_invalide, ambiguClé dans l'adresse ; paramètre mal orthographié (la liste acceptée est dans details) ou hors bornes ; nom de cuvée ambigu (candidats dans details).
401cle_absente, authentification_non_supportee, cle_mal_formee, cle_inconnue, cle_revoquee, cle_expiree, acces_retirePas d'en-tête, autre schéma que Bearer, clé tronquée ou inconnue, révoquée, expirée, ou la personne n'a plus accès à l'exploitation.
403portee_insuffisante, permission_refusee, module_indisponibleLa clé n'a pas la portée ; le rôle de la personne ne le permet plus ; module fermé pour l'exploitation.
404introuvable, route_inconnueCuvée ou facture inconnue ; adresse qui n'existe pas (sans barre finale).
405methode_non_autoriseeAutre méthode que GET : l'API est en lecture seule.
429trop_de_requetes, trop_d_echecsLimite atteinte : attendez la durée de l'en-tête Retry-After (secondes).
503service_indisponibleLe compteur de limitation ne répond pas : réessayez après Retry-After.

Limites

Chaque réponse authentifiée porte X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset (secondes avant la nouvelle fenêtre). Les listes sont plafonnées comme au connecteur (par exemple 50 factures au plus).

Référence des points

Cette référence est engendrée depuis la description OpenAPI 1.0.0 que sert Mon Chai : https://tester.monchai.fr/api/v1/openapi.json (publique, sans clé). Tous les points sont des GET.

GET /api/v1/moi

Exploitation, utilisateur, rôle et portées de la clé. À appeler en premier.

Aucune portée exigée. Outil du connecteur équivalent : contexte_connexion. Réponses : 200, 401, 403, 405, 429.

GET /api/v1/stocks

Résumé des stocks : vrac en litres, bouteilles au total, par format et par cuvée.

Portée : stocks:lecture. Outil du connecteur équivalent : stock_resume. Réponses : 200, 401, 403, 405, 429.

GET /api/v1/stocks/vrac

Vin en vrac (cuves, lots techniques) en litres, par lot.

Portée : stocks:lecture. Outil du connecteur équivalent : stock_vrac. Réponses : 200, 401, 403, 405, 429.

GET /api/v1/stocks/cuvees/{cuvee}

Stock d'une cuvée par son nom (exact, sinon « contient ») : bouteilles par format et lots commerciaux.

Portée : stocks:lecture. Outil du connecteur équivalent : stock_par_cuvee. Réponses : 200, 400, 401, 403, 404, 405, 429.

ParamètreOùDescription
cuvee obligatoirecheminNom de la cuvée (encodé dans l'adresse).

GET /api/v1/stocks/formats/{format_ml}

Lots commerciaux d'un format en millilitres (750 bouteille, 1500 magnum, 375 demi).

Portée : stocks:lecture. Outil du connecteur équivalent : stock_par_format. Réponses : 200, 400, 401, 403, 405, 429.

ParamètreOùDescription
format_ml obligatoirecheminFormat en millilitres, entre 50 et 30000.

GET /api/v1/factures

Factures (ventes par défaut, achats avec sens=purchase), filtrables par statut, période et client ; triées par date d'émission décroissante ; au plus 50.

Portée : factures:lecture. Outil du connecteur équivalent : factures_lister. Réponses : 200, 400, 401, 403, 405, 429.

ParamètreOùDescription
statutrequêteStatut de la facture. Valeurs : draft, sent, validated, executed, issued, paid, cancelled.
durequêteDébut de période (date d'émission), AAAA-MM-JJ.
aurequêteFin de période (date d'émission), AAAA-MM-JJ.
clientrequêtePartie du nom du client (100 caractères au plus).
sensrequêtesale (ventes) ou purchase (achats). Valeurs : sale, purchase. Par défaut : sale.
limiterequêteNombre de factures rendues (1 à 50). Par défaut : 20.

GET /api/v1/factures/impayees

Factures de vente émises non soldées (avoirs déduits), total dû et échues.

Portée : factures:lecture. Outil du connecteur équivalent : factures_impayees. Réponses : 200, 400, 401, 403, 405, 429.

ParamètreOùDescription
aurequêteFin de période (date d'émission), AAAA-MM-JJ.

GET /api/v1/factures/{numero}

Détail d'une facture ou d'un avoir par son numéro : en-tête, lignes, règlements.

Portée : factures:lecture. Outil du connecteur équivalent : facture_detail. Réponses : 200, 400, 401, 403, 404, 405, 429.

ParamètreOùDescription
numero obligatoirecheminNuméro (ou référence) de la facture ou de l'avoir.

GET /api/v1/chiffre-affaires

Chiffre d'affaires sur une période : factures et avoirs de vente émis ou payés, net HT et TTC.

Portée : factures:lecture. Outil du connecteur équivalent : chiffre_affaires. Réponses : 200, 400, 401, 403, 405, 429.

ParamètreOùDescription
durequêteDébut de période (date d'émission), AAAA-MM-JJ.
aurequêteFin de période (date d'émission), AAAA-MM-JJ.

Exemples complets

Ils lisent la clé dans la variable d'environnement MON_CHAI_CLE — jamais écrite dans le code. Dans un terminal (bash, zsh, Git Bash) :

export MON_CHAI_CLE="mc_live_…"   # collez votre clé ; PowerShell : $env:MON_CHAI_CLE = "…"

Mes stocks (curl)

curl -s "https://tester.monchai.fr/api/v1/stocks" \
  -H "Authorization: Bearer $MON_CHAI_CLE"

Mes impayés (curl)

curl -s "https://tester.monchai.fr/api/v1/factures/impayees" \
  -H "Authorization: Bearer $MON_CHAI_CLE"

Mes stocks et mes impayés (Python)

Installation : pip install httpx — lancement : python api_mes_donnees.py. Fichier api_mes_donnees.py, à copier tel quel :

"""Mes stocks et mes impayés par l'API REST v1 de Mon Chai — exemple complet en Python.

Avant de lancer :
  1. dans Mon Chai, Administration › Connecteur IA & clés d'API › « Clés d'API
     (vos programmes) », créez une clé avec les portées « Stocks » et
     « Factures et chiffre d'affaires » ; copiez-la, elle ne sera plus affichée ;
  2. installez le client HTTP :   pip install httpx
  3. donnez la clé au script par une variable d'environnement, jamais dans le code :
       macOS / Linux :        export MON_CHAI_CLE="mc_live_…"
       Windows PowerShell :   $env:MON_CHAI_CLE = "mc_live_…"

Lancement :
    python api_mes_donnees.py
Autre adresse Mon Chai :  MON_CHAI_URL=https://… python api_mes_donnees.py
"""
import os

import httpx

MON_CHAI = os.environ.get("MON_CHAI_URL", "https://tester.monchai.fr").rstrip("/")
CLE = os.environ.get("MON_CHAI_CLE", "")


def lire(client: httpx.Client, chemin: str) -> dict:
    """Un GET sur l'API ; en cas de refus, le code et le message de Mon Chai."""
    reponse = client.get(chemin)
    corps = reponse.json()
    if reponse.status_code != 200:
        erreur = corps["erreur"]
        attente = reponse.headers.get("Retry-After")
        raise SystemExit(f"{reponse.status_code} {erreur['code']} : {erreur['message']}"
                         + (f" (réessayer dans {attente} s)" if attente else ""))
    return corps


def main() -> None:
    if not CLE:
        raise SystemExit("Définissez la variable d'environnement MON_CHAI_CLE (votre clé d'API).")
    entetes = {"Authorization": f"Bearer {CLE}"}
    with httpx.Client(base_url=MON_CHAI + "/api/v1", headers=entetes, timeout=30) as client:
        moi = lire(client, "/moi")
        print("Exploitation :", moi["exploitation"], "— portées :", ", ".join(moi["portee"]))

        stocks = lire(client, "/stocks")
        print("Bouteilles :", stocks["bouteilles_total"], "— vrac :", stocks["vrac_litres"], "L")
        for ligne in stocks["par_cuvee"]:
            print(f"  {ligne['cuvee']} : {ligne['bouteilles']} bouteilles")

        impayes = lire(client, "/factures/impayees")
        if impayes["etat"] == "empty":
            print("Aucune facture impayée.")
            return
        print(f"{impayes['nombre']} facture(s) impayée(s), {impayes['nombre_echues']} échue(s)"
              f" — total dû : {impayes['montant_du_total']} €")
        for facture in impayes["factures"]:
            print(f"  {facture['numero']}  {facture['client']}  reste dû {facture['reste_du']} €"
                  f"  échéance {facture['date_echeance'] or '—'}")


if __name__ == "__main__":
    main()

Mes stocks et mes impayés (TypeScript)

Installation : aucune dépendance (fetch de Node.js 18+) ; tsx pour exécuter le TypeScript — lancement : npx tsx api_mes_donnees.ts. Fichier api_mes_donnees.ts, à copier tel quel :

/**
 * Mes stocks et mes impayés par l'API REST v1 de Mon Chai — exemple complet en TypeScript.
 *
 * Avant de lancer :
 *   1. dans Mon Chai, Administration › Connecteur IA & clés d'API › « Clés d'API
 *      (vos programmes) », créez une clé avec les portées « Stocks » et
 *      « Factures et chiffre d'affaires » ; copiez-la, elle ne sera plus affichée ;
 *   2. donnez la clé au script par une variable d'environnement, jamais dans le code :
 *        macOS / Linux :        export MON_CHAI_CLE="mc_live_…"
 *        Windows PowerShell :   $env:MON_CHAI_CLE = "mc_live_…"
 *
 * Lancement (Node.js 18 ou plus récent, aucune dépendance : fetch est intégré) :
 *   npx tsx api_mes_donnees.ts        (ou, avec Node.js 23.6+ :  node api_mes_donnees.ts)
 * Autre adresse Mon Chai :  MON_CHAI_URL=https://… npx tsx api_mes_donnees.ts
 *
 * À exécuter côté serveur ou dans un script : jamais dans une page web, la clé
 * y serait lisible par tous (et l'API n'envoie pas d'en-têtes CORS : un
 * navigateur refuserait de toute façon la réponse).
 */
const MON_CHAI = (process.env.MON_CHAI_URL ?? "https://tester.monchai.fr").replace(/\/+$/, "");
const CLE = process.env.MON_CHAI_CLE ?? "";

/** Un GET sur l'API ; en cas de refus, le code et le message de Mon Chai. */
async function lire(chemin: string): Promise<any> {
  const reponse = await fetch(`${MON_CHAI}/api/v1${chemin}`, {
    headers: { Authorization: `Bearer ${CLE}` },
  });
  const corps = await reponse.json();
  if (!reponse.ok) {
    const attente = reponse.headers.get("Retry-After");
    throw new Error(`${reponse.status} ${corps.erreur.code} : ${corps.erreur.message}`
      + (attente ? ` (réessayer dans ${attente} s)` : ""));
  }
  return corps;
}

async function main() {
  if (!CLE) throw new Error("Définissez la variable d'environnement MON_CHAI_CLE (votre clé d'API).");

  const moi = await lire("/moi");
  console.log(`Exploitation : ${moi.exploitation} — portées : ${moi.portee.join(", ")}`);

  const stocks = await lire("/stocks");
  console.log(`Bouteilles : ${stocks.bouteilles_total} — vrac : ${stocks.vrac_litres} L`);
  for (const ligne of stocks.par_cuvee) {
    console.log(`  ${ligne.cuvee} : ${ligne.bouteilles} bouteilles`);
  }

  const impayes = await lire("/factures/impayees");
  if (impayes.etat === "empty") {
    console.log("Aucune facture impayée.");
    return;
  }
  console.log(`${impayes.nombre} facture(s) impayée(s), ${impayes.nombre_echues} échue(s) — total dû : ${impayes.montant_du_total} €`);
  for (const facture of impayes.factures) {
    console.log(`  ${facture.numero}  ${facture.client}  reste dû ${facture.reste_du} €  échéance ${facture.date_echeance ?? "—"}`);
  }
}

main().catch((erreur) => {
  console.error(erreur.message ?? erreur);
  process.exit(1);
});

Ces commandes et ces deux fichiers sont ceux que Mon Chai exécute contre un serveur réel, avec une clé de test, pour vérifier cette page.