Pour les éditeurs de LGO, de contrôle de remises et de SaaS pharmacie

L'optimisation des achats génériques Margen, dans votre logiciel.

Envoyez vos achats, vos RSF et vos remises arrière. Recevez la meilleure répartition par labo et par CIP, l'économie chiffrée, et les volumes prévus pour l'année. Sandbox gratuite, puis 290 € HT par mois avec 30 officines actives incluses.

Vous êtes un groupement et vous n'éditez pas de logiciel ? Utilisez l'application web →

POST /v1/optimize

Quels CIP acheter, chez quel labo, pour payer le moins cher net de remises. Économie chiffrée par groupe générique et par labo.

Volumes prévus inclus

Pour l'année en cours ou la suivante, le résultat donne aussi les volumes prévus mois par mois, sur lesquels la recommandation est calculée.

En bref. URL de base https://public-api.margen.fr, JSON en entrée et en sortie, clé dans l'en-tête Authorization: Bearer mgn_test_…. Le prix (PFHT), les groupes génériques et les ruptures viennent du référentiel Margen : vous n'envoyez que vos achats et vos conditions commerciales.

1 Obtenir une clé

  1. Créez votre compte dans la console et confirmez votre e-mail.
  2. Activation sous 24 h ouvrées : la console indique quand c'est fait.
  3. Une fois validé, créez une clé de test mgn_test_…. Elle n'est affichée qu'une fois : copiez-la.

Vérifiez qu'elle fonctionne : la réponse indique votre offre et le quota restant.

Terminal
export MARGEN_API_KEY=mgn_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

curl -sS https://public-api.margen.fr/v1/usage -H "Authorization: Bearer $MARGEN_API_KEY"

2 Vérifier vos CIP et trouver les labo_id

Facultatif mais recommandé avant le premier appel. Ces deux requêtes sont gratuites (hors quota).

Terminal
# Vos CIP sont-ils connus ? (groupe générique, labo, PFHT en vigueur)
curl -sS "https://public-api.margen.fr/v1/reference/generics?cip=3400930000014,3400930000021" \
  -H "Authorization: Bearer $MARGEN_API_KEY"

# Identifiants des labos (labo_id), pour vos RSF et remises arrière
curl -sS https://public-api.margen.fr/v1/reference/labos -H "Authorization: Bearer $MARGEN_API_KEY"
Réponse (extrait)
{
  "object": "list",
  "data": [
    {
      "cip": "3400930000014",
      "label": "…",
      "gen_group_id": "…",
      "labo_id": 12,
      "labo": "…",
      "is_generic": true,
      "pfht_eur": 2.41
    }
  ],
  "not_found": ["3400930000021"]
}

3 Préparer la requête

Le minimum : vos achats. Ajoutez vos RSF pour un résultat réaliste. Enregistrez ce fichier sous optimize.json.

optimize.json
{
  "year": 2026,
  "purchases": [
    { "finess": "750000010", "cip": "3400930000014", "month": "2026-01", "qty": 120 },
    { "finess": "750000010", "cip": "3400930000014", "month": "2026-02", "qty": 98 },
    { "finess": "750000028", "cip": "3400930000021", "month": "2026-01", "qty": 40 }
  ],
  "rsf": [
    { "cip": "3400930000014", "rate_pct": 30 },
    { "cip": "3400930000021", "rate_pct": 22.5 },
    { "labo_id": 12, "rate_pct": 17 }
  ]
}
ChampDescription
purchases requisUne ligne par officine × CIP × mois : finess (9 chiffres), cip (CIP13), month (« AAAA-MM »), qty (boîtes nettes).
rsf Remises sur facture négociées, en % (voir ci-dessous). Sans RSF, le taux est 0 %.
remises_arrieres Programmes de remises arrière par labo, avec leurs paliers.
year Année analysée. Par défaut : l'année en cours (l'année passée en backtest, la suivante en forecast_next).
mode current_year (défaut), backtest (rejouer une année passée) ou forecast_next (année suivante).
scope groupement (défaut, achats mutualisés) ou per_officine (un calcul par FINESS).

Les RSF : par CIP, par labo, groupement ou officine

  • • cip + rate_pct : le taux négocié pour ce CIP. C'est le cas courant.
  • • labo_id sans cip : taux par défaut pour tous les autres CIP de ce labo.
  • • Sans finess, le taux vaut pour tout le groupement. Avec finess, il ne vaut que pour cette officine (avec "scope": "per_officine").
  • • Si plusieurs taux s'appliquent, le plus précis gagne : officine + CIP, puis officine + labo, puis CIP, puis labo, sinon 0 %.
  • • Taux variables dans l'année : ajoutez valid_from / valid_to (« AAAA-MM-JJ »).

Les remises arrière (facultatif)

Un programme par labo. Ici : 3 % jusqu'à 50 000 € d'achats (PFHT), 6 % au-delà. Ajoutez ce bloc au même niveau que purchases. Le plafond légal (RSF + remise arrière, art. L.138-9 CSS : 40 % pour les génériques en 2026, suivi année par année) est appliqué automatiquement.

optimize.json (suite)
"remises_arrieres": [
  {
    "labo_id": 12,
    "type": "threshold_bands",
    "tiers": [
      { "min_eur": 0,     "max_eur": 50000, "rate_pct": 3 },
      { "min_eur": 50000,                   "rate_pct": 6 }
    ]
  }
]

Vous avez déjà les lignes de facture ?

Contrôle de remises, réception financière, coffre-fort de factures : vous tenez déjà une ligne par facture et par CIP, avec la quantité et la remise réellement appliquée. C'est l'entrée de l'optimiseur. Trois règles d'agrégation suffisent.

1. Le mapping

Colonne de factureChamp APIRègle
FINESS de l'officinepurchases[].finessTel quel (9 chiffres).
Code CIP (13 ou 7)purchases[].cipTel quel.
Date de facturepurchases[].monthTronquée au mois, « AAAA-MM ».
Quantité (avoirs en négatif)purchases[].qtySomme par officine × CIP × mois.
Remise sur facture appliquée (%)rsf[].rate_pctPar CIP : le taux le plus fréquent de l'année, pondéré par les boîtes. Avec finess en per_officine.
Prix unitaire, net HT, fournisseur—Non envoyés : le PFHT, le labo et le groupe générique viennent du référentiel Margen.

Factures avec le montant de la remise seulement : taux = remise ÷ (quantité × prix unitaire facturé).

2. Un exemple

Quatre lignes de facture d'une officine, dont un avoir…

Vos lignes de facture
FINESS     Date        CIP            Quantité  Remise %
130001233  2026-01-05  3400937290494        80        30
130001233  2026-01-19  3400937290494        56        30
130001233  2026-02-25  3400937290494        -2        30   ← avoir
130001233  2026-01-05  3400937199155        34        25

…deviennent trois achats mensuels et deux taux de RSF :

optimize.json
{
  "scope": "per_officine",
  "purchases": [
    { "finess": "130001233", "cip": "3400937290494", "month": "2026-01", "qty": 136 },
    { "finess": "130001233", "cip": "3400937290494", "month": "2026-02", "qty": 0 },
    { "finess": "130001233", "cip": "3400937199155", "month": "2026-01", "qty": 34 }
  ],
  "rsf": [
    { "finess": "130001233", "cip": "3400937290494", "rate_pct": 30 },
    { "finess": "130001233", "cip": "3400937199155", "rate_pct": 25 }
  ]
}

3. Ce que vous récupérez

summary.savings_eur
Ce que l'officine aurait payé en moins sur l'année en achetant chaque groupe générique au bon labo.
to_buy[]
Le plan d'achat par CIP pour les mois restants, prêt à alimenter votre export de prix nets vers le LGO.

Le résultat repose sur les remises telles qu'elles ont été facturées, pas telles qu'elles ont été promises. Un script de conversion CSV → requête est fourni sur demande à contact@margen.fr.

4 Lancer l'optimisation

Prefer: wait=60 demande d'attendre le résultat jusqu'à 60 secondes. Idempotency-Key évite d'être décompté deux fois si vous renvoyez la même requête.

200 — c'est fini

Le résultat est dans la réponse.

202 — encore en cours

Interrogez GET /v1/jobs/{id} toutes les 5 s ; le résultat est dans result.

curl
curl -sS https://public-api.margen.fr/v1/optimize \
  -H "Authorization: Bearer $MARGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Prefer: wait=60" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d @optimize.json

# Réponse 202 ? Le calcul continue : interrogez le job jusqu'à "status": "succeeded"
curl -sS https://public-api.margen.fr/v1/jobs/JOB_ID -H "Authorization: Bearer $MARGEN_API_KEY"

5 Lire le résultat

Les montants sont en euros, nets de RSF et de remises arrière. Les valeurs ci-dessous sont illustratives.

Réponse (extrait)
{
  "object": "optimize_result",
  "year": 2026,
  "scope": "groupement",
  "summary": {
    "hist_effective_eur": 18240.50,
    "opt_effective_eur": 16912.10,
    "savings_eur": 1328.40,
    "savings_rate": 0.0728
  },
  "units": [
    {
      "finess": null,
      "by_gen_group": [
        {
          "gen_group_id": "…",
          "label": "…",
          "delta_eur": -412.30,
          "current":     [ { "cip": "3400930000021", "labo_id": 52, "qty": 1400, … } ],
          "recommended": [ { "cip": "3400930000014", "labo_id": 12, "qty": 1400, … } ]
        }
      ],
      "by_labo": [ … ]
    }
  ],
  "warnings": []
}
summary.savings_eur
Économie totale par rapport aux achats tels qu'ils ont été faits (net de RSF et remises arrière).
units[]
Un élément pour le groupement, ou un par officine en scope per_officine (finess renseigné).
by_gen_group[].to_buy
Ce qu'il faut acheter à partir de maintenant : CIP, labo et boîtes, pour les mois restants (année en cours) ou toute l'année (année suivante).
by_gen_group[].recommended
La répartition optimale sur l'année entière (mois déjà achetés inclus tels qu'achetés) ; current = les achats réels.
by_labo[]
Montants par labo, palier de remise arrière atteint et reste à acheter pour le palier suivant.
warnings[]
Points d'attention (CIP inconnus, lignes ignorées, plafond légal dépassé…).

Les résultats restent disponibles 7 jours sur GET /v1/jobs/{id} ; DELETE /v1/jobs/{id} les efface tout de suite.

Pour le montrer à un pharmacien : le générateur de rapport transforme un résultat en page imprimable par officine, à votre nom, dans le navigateur.

6 Optimiser l'année en cours ou la suivante

Le même appel POST /v1/optimize couvre trois cas, choisis avec mode. Quand l'année n'est pas terminée, Margen prévoit les volumes des mois restants à partir de votre historique et optimise sur l'année complète.

current_yearDéfaut. L'année en cours : achats déjà faits + volumes prévus jusqu'en décembre.
forecast_nextL'année suivante, entièrement à partir des volumes prévus. Envoyez l'historique jusqu'à aujourd'hui.
backtestUne année passée complète, rejouée : aucune prévision, tout est réel.

Chaque groupe générique indique alors ce qui est déjà acheté (purchased_qty), ce qui est prévu (forecast_qty) et le détail par mois (forecast_months) : qty = purchased_qty + forecast_qty. to_buy donne les CIP à acheter pour ces mois restants (toute l'année en forecast_next). Une prévision marquée "forecast_confidence": "limited" repose sur un historique court (moins de 14 mois) : envoyez 24 mois d'historique quand c'est possible.

Réponse current_year (extrait)
"units": [
  {
    "last_data_month": 9,
    "forecast_from": "2026-10",
    "by_gen_group": [
      {
        "gen_group_id": "…",
        "qty": 1480,
        "purchased_qty": 1110,
        "forecast_qty": 370,
        "forecast_confidence": "standard",
        "forecast_months": [
          { "month": "2026-10", "qty": 124 },
          { "month": "2026-11", "qty": 121 },
          { "month": "2026-12", "qty": 125 }
        ],
        "to_buy": [
          { "cip": "3400930000014", "labo_id": 12, "qty": 370, "months": [10, 11, 12], … }
        ],
        "recommended": [ … ]
      }
    ]
  }
]

Erreurs

Toujours le même format : { "error": { "type", "code", "message", "rows" }, "request_id" }. Donnez le request_id au support si besoin.

HTTPcodeQue faire
400finess_required_liveAvec une clé live, chaque ligne d'achat doit porter le FINESS de l'officine (la facturation compte les officines actives).
400invalid_rowsLignes invalides : chacune est listée dans error.rows avec son chemin (ex. purchases[3].cip).
413too_many_rowsRequête trop grosse pour votre offre (aussi too_many_officines) : découpez-la.
401invalid_api_keyClé inconnue. Variantes : missing_api_key (en-tête absent), api_key_revoked (clé révoquée).
402quota_exceededQuota mensuel épuisé (Sandbox) ; il se renouvelle le 1er du mois. Passez en Partner pour lever la limite.
403account_pendingCompte en attente de validation par l'équipe Margen.
429rate_limitedTrop de requêtes : attendez la durée indiquée par Retry-After.
503free_capacity_reachedCapacité Sandbox du jour atteinte : réessayez après minuit UTC (Retry-After), ou passez en Partner.

Liste complète dans la référence de l'API (openapi.yaml).

Unités et limites

Une optimisation = un calcul (un par officine en per_officine). Les calculs en échec ou annulés ne sont pas décomptés. En Sandbox : 20 optimisations par mois, 10 officines par requête, 2 calculs en parallèle. Les clés de test gardent ces limites sur toutes les offres ; les clés live suivent celles de votre offre (tarifs).

Vos données

  • • Les achats envoyés sont traités en mémoire et jamais stockés.
  • • Les résultats sont conservés 7 jours, puis supprimés.
  • • Hébergement dans l'Union européenne. Margen agit en sous-traitant (article 28 du RGPD) : conditions et DPA.

Construire ou intégrer ?

Avec un assistant de code, le solveur s'écrit en quelques jours. Ce qui ne se génère pas : la vingtaine de règles commerciales et légales qu'il faut connaître avant d'écrire la première ligne, le référentiel reconstruit chaque nuit, et la preuve que le chiffre est juste avant de le montrer à un pharmacien. Le détail, et le calcul coût interne contre API →

Nos engagements envers les éditeurs partenaires

  • • Votre marque, votre prix. Le résultat est le vôtre ; Margen n'apparaît que si vous le souhaitez.
  • • Vos clients restent vos clients. Margen ne démarche pas les officines équipées par un partenaire, pendant toute la durée du partenariat. Pour les groupements, nous co-vendons avec vous plutôt que contre vous.
  • • Un pilote avant tout engagement. Backtest gratuit sur un échantillon de vos officines, chiffre par officine sous une semaine, puis pilote sans frais.
  • • Pas de rétention. Vos données ne sont jamais stockées ; si vous arrêtez, il n'y a rien à récupérer chez nous.

Pour en parler : Clément Lefèvre, fondateur de margen, gérant de timeit srl, contact@margen.fr.

Tarifs de l'API

Prix hors taxes, sans engagement, résiliable chaque mois. Une officine active est un FINESS présent dans au moins une optimisation réussie avec une clé live au cours du mois civil : une officine optimisée dix fois dans le mois est comptée une fois. Les clés de test ne sont jamais facturées.

Intégrer et tester

API Sandbox

0 €

sans carte bancaire

  • Clés de test mgn_test_
  • 20 optimisations / mois
  • 10 officines et 50 000 lignes par requête
  • 10 requêtes / minute
Obtenir une clé

Éditeurs de LGO et SaaS pharmacie

API Partner

290 €

HT / mois · 30 officines actives incluses

Puis, par officine active et par mois
31 – 2009 €
201 – 1 0007 €
> 1 0005 €
  • Clés live, facturation à l'officine active
  • Jusqu'à 5 000 officines et 2 000 000 lignes par requête
  • 120 requêtes / minute, 5 calculs en parallèle
  • Webhooks signés
  • Souscription en ligne, facture mensuelle
Passer en Partner

Grands réseaux, au-delà de 5 000 officines

API Enterprise

Sur devis

contrat annuel

  • Prix dégressif négocié
  • Instance dédiée, SLA et support prioritaire
  • Marque blanche
  • Accord de traitement des données sur mesure
Nous contacter

Prêt à commencer ?

Créez votre compte développeur et une clé de test : la Sandbox est gratuite, sans carte bancaire. Passez en Partner depuis la console quand vous êtes prêt.

Obtenir une clé