Aller au contenu

API publique v1

L’API publique permet à un logiciel tiers de lire les données d’une société OMAG : Power BI, Excel, un site de vente en ligne, un ERP voisin, ou un développeur mandaté par le client.

Une société de démonstration est ouverte à tous. Copiez la clé ci-dessous et appelez l’API : pas d’inscription, rien à installer.

Fenêtre de terminal
curl "https://api.omag.ma:7979/api/v1/moi" \
-H "X-Omag-Cle: omk_live_1_FVhCzt_l2X10HJM5lvxRjUMZtuDddaO_"

Elle ouvre toutes les portées en lecture sur un jeu de données fictif — 47 articles, 19 clients, 222 factures, 4 dépôts — et supporte tout ce qui est décrit dans cette page : pagination, synchronisation incrémentale, flux BI, export CSV.

0. Vérifier que l’option est active. L’API fait partie du module « API & connecteurs IA », visible dans Mes applications. S’il n’est pas actif, les appels répondent 403 MODULE_NON_SOUSCRIT — il faut le demander à OMAG.

1. Obtenir une clé. L’administrateur du compte OMAG la crée lui-même dans Configuration → Clés API : un libellé, les portées à cocher, un quota. La clé s’affiche une seule fois — le serveur n’en garde que l’empreinte. Côté administrateur, la marche à suivre est décrite dans Connecter un autre logiciel.

2. Vérifier qu’elle fonctionne.

Fenêtre de terminal
curl https://api.omag.ma:7979/api/v1/moi \
-H "X-Omag-Cle: omk_live_47_VOTRE_CLE"
{
"cle": "omk_live_47_3JyZN7",
"libelle": "Power BI direction",
"societe": "omag_47_MA SOCIETE",
"scopes": ["articles:read", "stock:read"],
"scopes_disponibles": ["articles:read", "stock:read", "tiers:read",
"documents:read", "reglements:read", "compta:read"]
}

3. Lire des données.

Fenêtre de terminal
curl "https://api.omag.ma:7979/api/v1/articles?limite=50" \
-H "X-Omag-Cle: omk_live_47_VOTRE_CLE"

La clé se présente dans l’en-tête X-Omag-Cle. Par commodité, Authorization: Bearer omk_live_... est également accepté — c’est le réflexe de tout client HTTP, et le refuser ne protégerait de rien.

omk_live_<IdClient>_<aléa base64url>

L’identifiant au milieu n’est pas un secret : c’est un routage. Chaque client OMAG possède sa propre base de configuration, et une clé nue ne dirait pas laquelle interroger. Le secret, c’est l’aléa (24 octets).

Une clé porte une société et une seule. C’est elle qui fixe le périmètre : aucune route de l’API ne prend de nom de base, ni dans l’URL ni dans le corps. Un client multi-sociétés crée une clé par société.

Conséquence directe : vous ne pouvez pas vous tromper de dossier, et vous ne pouvez pas atteindre celui de quelqu’un d’autre.

Une clé n’ouvre que ce qui a été coché à sa création.

Portée Ouvre
articles:read Articles
stock:read Stock et disponibilités
tiers:read Clients et fournisseurs
documents:read Ventes : devis, commandes, BL, factures, avoirs
achats:read Achats : commandes, réceptions, factures, avoirs, règlements fournisseurs
reglements:read Règlements clients
compta:read Écritures comptables, balance

GET /v1/moi liste celles que porte votre clé ; GET /v1/flux indique en plus, pour chaque vue BI, si votre clé y a droit.

Plafond par clé et par minute (60 par défaut, réglable par l’administrateur).

Chaque réponse porte votre compteur — pas seulement les refus :

En-tête
RateLimit-Limit votre plafond par minute
RateLimit-Remaining appels restants dans la fenêtre en cours
RateLimit-Reset secondes avant remise à zéro

Au-delà du plafond : 429 avec, en plus, un Retry-After en secondes — toujours égal à RateLimit-Reset.

Lisez RateLimit-Remaining et ralentissez avant d’arriver à zéro : c’est plus simple que de gérer des 429, et ça évite de perdre des requêtes.

Depuis un navigateur, ces en-têtes sont explicitement exposés (Access-Control-Expose-Headers), donc lisibles en JavaScript.

Le quota est décompté même sur un refus de portée ou d’adresse : un appel mal formé coûte quand même une recherche de clé. Votre compteur reste donc exact quoi qu’il arrive.

Ressources REST Flux à plat
Chemin /v1/<ressource> /v1/flux/<vue>
Pour qui un développeur Power BI, Excel, Looker Studio
Forme objets, clés naturelles lignes plates, déjà jointes et agrégées
Pagination curseur opaque numéro de page
Sortie JSON JSON ou CSV

Ce n’est pas une incohérence : un outil de BI se débrouille mal avec un curseur, un développeur se débrouille mal avec un jeu pré-agrégé. Les deux familles partagent la même clé et les mêmes portées.

Route Portée Réponse
GET /v1 ouverte sonde { api, version, statut }
GET /v1/moi clé valide identité de la clé
GET /v1/articles articles:read liste
GET /v1/articles/{code} articles:read fiche
GET /v1/stock stock:read une ligne par article et par dépôt
GET /v1/tiers/clients tiers:read liste
GET /v1/tiers/clients/{code} tiers:read fiche
GET /v1/tiers/fournisseurs tiers:read liste
GET /v1/tiers/fournisseurs/{code} tiers:read fiche
GET /v1/documents/{type} documents:read en-têtes seulement
GET /v1/documents/{type}/{numero} documents:read en-tête + lignes
GET /v1/achats/documents/{type} achats:read en-têtes seulement
GET /v1/achats/documents/{type}/{numéro} achats:read en-tête + lignes
GET /v1/achats/reglements achats:read liste
GET /v1/achats/reglements/{numéro} achats:read fiche
GET /v1/reglements reglements:read liste
GET /v1/reglements/{numero} reglements:read fiche
GET /v1/compta/ecritures compta:read liste
GET /v1/postman clé valide collection Postman prête à importer

{type} vaut devis, commandes, bl, factures ou avoirsune seule forme de réponse pour les cinq. Un analyseur écrit pour les factures lit les devis sans une ligne de changement.

La liste de documents ne porte pas les lignes : les joindre ferait exploser une page de 200 documents alors que la plupart des intégrations n’en ont pas besoin. Qui veut le détail demande la fiche.

Côté achats, {type} vaut commandes, receptions, factures ou avoirs. La réponse a exactement la même forme que côté ventes, au nom du tiers près : fournisseur_code et fournisseur_nom remplacent client_code et client_nom. Un analyseur écrit pour l’un lit l’autre en changeant deux noms.

La sonde GET /v1 est volontairement anonyme : elle vous permet de distinguer « le service est injoignable » de « ma clé est refusée ».

Paramètre Défaut Effet
limite 200 (max 1000) taille de page
curseur page suivante ; valeur opaque, à renvoyer telle quelle
modifie_depuis bascule en mode incrémental (date ISO)

Chaque liste accepte des filtres nommés, combinés en ET, et compatibles avec la pagination comme avec le mode incrémental.

Ressource Filtres
articles recherche, famille, sous_famille, code_barre, bloque
stock article, depot
tiers/clients recherche, ville, bloque, prospect
tiers/fournisseurs recherche, ville
documents/{type} client, du, au, impaye (sauf devis, qui n’a pas de règlement)
achats/documents/{type} fournisseur, du, au, impaye (sauf commandes)
achats/reglements fournisseur, du, au, mode
reglements client, du, au, mode
compta/ecritures compte, journal, exercice, du, au, lettre, non_lettre
Fenêtre de terminal
# Les factures impayées d'un client sur 2026
GET /v1/documents/factures?client=000055&du=2026-01-01&au=2026-12-31&impaye=1
# Tout le compte clients non lettré
GET /v1/compta/ecritures?compte=3421&non_lettre=1
# Le stock d'un dépôt
GET /v1/stock?depot=1

Conventions :

  • du / au sont inclusifs, au format AAAA-MM-JJ.
  • compte filtre par préfixe : compte=34 rend tous les comptes 34xxx.
  • recherche porte sur plusieurs colonnes à la fois (code, libellé, référence, code-barre pour les articles ; nom, code, e-mail, téléphone, ICE pour les tiers).
  • Les booléens acceptent 1/0, true/false, oui/non.
{
"donnees": [ /* … */ ],
"curseur_suivant": "ART0042",
"supprimes": ["ART0007"]
}

curseur_suivant à null signifie fin du parcours. supprimes n’apparaît qu’en mode incrémental.

Sans modifie_depuis, vous parcourez la table entière — le chargement initial. Avec, vous ne recevez que ce qui a bougé depuis. Une seule mécanique à coder, et le chargement de masse comme le rafraîchissement fréquent en sortent.

Fenêtre de terminal
# 1) chargement complet, page par page
GET /v1/articles?limite=500
GET /v1/articles?limite=500&curseur=<curseur_suivant>
…jusqu'à curseur_suivant = null
# 2) puis, toutes les heures
GET /v1/articles?modifie_depuis=2026-09-13T08:00:00

Les suppressions sont couvertes. C’est le trou classique de toute synchronisation incrémentale : une ligne effacée est invisible d’une requête sur la table. Ici elle sort dans supprimes. Traitez ce tableau comme une liste de clés à retirer de votre copie.

Seule la dernière action de chaque clé compte dans la fenêtre : une ligne créée puis supprimée ne remonte pas comme « modifiée », une ligne supprimée puis recréée ne remonte pas comme « supprimée ».

import requests
BASE = "https://api.omag.ma:7979/api/v1"
EN_TETES = {"X-Omag-Cle": "omk_live_47_VOTRE_CLE"}
def tout_lire(ressource, **params):
curseur, lignes = None, []
while True:
p = {"limite": 500, **params}
if curseur:
p["curseur"] = curseur
r = requests.get(f"{BASE}/{ressource}", headers=EN_TETES, params=p, timeout=60)
r.raise_for_status()
page = r.json()
lignes += page["donnees"]
curseur = page.get("curseur_suivant")
if not curseur:
return lignes
articles = tout_lire("articles")
print(len(articles), "articles")
Vue Portée Contenu
GET /v1/flux clé valide catalogue : vues, paramètres, et ce que votre clé ouvre
GET /v1/flux/ventes documents:read CA par année, mois, agence, commercial, client, ville, secteur, famille, article
GET /v1/flux/balance compta:read balance comptable
GET /v1/flux/stock stock:read stock par article et dépôt, valorisé au PMP
GET /v1/flux/reglements reglements:read encaissements à plat
Paramètre Défaut
page 1 numéro de page
taille 5000 (max 20000) lignes par page
format json csv pour Excel
du / au période AAAA-MM-JJ, au inclus

ventes accepte base_ca, avec le même sens que le sélecteur « Base du CA » de l’écran Analyse croisée :

Valeur Définition
LIV (défaut) CA livré : BL au mois du BL + factures directes. Stable dans le temps.
FAC CA facturé : factures et avoirs seuls. Rapprochable avec la comptabilité et la TVA.
MIX Situation à date : factures + BL pas encore facturés. Un mois passé se recalcule à chaque facturation.

Une valeur inconnue retombe sur LIV.

Elle expose les à-nouveaux et les mouvements de la période séparément :

Champ
debit_report, credit_report à-nouveaux
debit_mouvement, credit_mouvement mouvements de la période
solde_debit, solde_credit soldes
solde signé : positif débiteur, négatif créditeur
sens D ou C

Un outil qui ne lirait qu’un couple « débit / crédit » produirait une balance fausse du montant des reports. Utilisez solde : il somme à zéro sur une balance équilibrée, ce qui vous donne un contrôle immédiat.

?format=csv rend un fichier à séparateur ; avec un BOM UTF-8 — les deux conditions pour qu’Excel français l’ouvre correctement, accents compris.

Fenêtre de terminal
curl "https://api.omag.ma:7979/api/v1/flux/ventes?du=2026-01-01&au=2026-12-31&format=csv" \
-H "X-Omag-Cle: omk_live_47_VOTRE_CLE" -o ventes-2026.csv

Power Query, Sources de données → Requête vide → Éditeur avancé :

let
Cle = "omk_live_47_VOTRE_CLE",
Base = "https://api.omag.ma:7979/api/v1",
Page = (n as number) as record =>
let
Reponse = Json.Document(Web.Contents(Base, [
RelativePath = "flux/ventes",
Query = [du = "2026-01-01", au = "2026-12-31",
taille = "20000", page = Text.From(n)],
Headers = [#"X-Omag-Cle" = Cle]
])),
Lignes = Table.FromRecords(Reponse[donnees]),
Total = Reponse[pages_total]
in
[Lignes = Lignes, Total = Total],
Premiere = Page(1),
Suivantes = List.Transform({2..Premiere[Total]}, each Page(_)[Lignes]),
Tout = Table.Combine(List.Combine({{Premiere[Lignes]}, Suivantes}))
in
Tout

Données → À partir du Web ne sait pas poser d’en-tête. Deux options :

  1. Le CSV : téléchargez-le avec curl et ouvrez-le. C’est le chemin le plus court.
  2. Power Query dans Excel : le même code M que ci-dessus — Excel embarque le même moteur que Power BI.
GET https://api.omag.ma:7979/api/v1/openapi.json

Publique, sans clé. C’est la description complète de l’API dans un format que les outils comprennent : toutes les routes, tous les paramètres avec leur type, tous les champs de chaque réponse.

Ce qu’elle vous fait gagner :

Essayer sans rien installer la page Essayer l’API la charge et la rend interactive
Générer un client openapi-generator produit une bibliothèque typée en C#, Python, PHP, Java… en quelques secondes
Importer dans vos outils Postman, Insomnia et Bruno avalent l’URL directement
Brancher une automatisation n8n, Make et consorts savent en construire un connecteur
Configurer un assistant IA un GPT personnalisé se configure en téléversant ce fichier
Fenêtre de terminal
# Un client Python en une commande
npx @openapitools/openapi-generator-cli generate -i https://api.omag.ma:7979/api/v1/openapi.json -g python -o ./client-omag
Fenêtre de terminal
curl https://api.omag.ma:7979/api/v1/postman \
-H "X-Omag-Cle: omk_live_47_VOTRE_CLE" -o omag-v1.postman_collection.json

Importez le fichier dans Postman, renseignez la variable cle dans l’onglet Variables de la collection, et toutes les requêtes fonctionnent. La collection est générée pour votre installation : l’adresse de base y est déjà correcte.

La clé n’est pas incluse dans le fichier, volontairement — un secret n’a rien à faire dans un fichier qu’on s’échange.

Dates : toujours AAAA-MM-JJ, en heure locale de la société. Elles ne sont jamais rendues en UTC — une date métier du 1er septembre ne doit pas s’afficher chez vous comme le 31 août.

Montants : toujours des nombres JSON, jamais des chaînes. Vous pouvez additionner sans conversion.

Ce qui sort :

  • Données validées uniquement. Un devis en cours de saisie n’est pas publiable. Il n’existe aucun paramètre pour outrepasser cette règle.
  • Les articles masqués et les tiers en sommeil sont exclus.
  • Les coûts (pmp_ht, dernier_prix_achat_ht) sortent dans articles:read. Une clé donnée à un prestataire lui donne donc accès aux marges : cette portée ne s’accorde qu’à qui doit l’avoir.
  • Pas de cloisonnement par agence ni par site : une clé n’est pas un utilisateur, elle voit tout le périmètre de sa société.

Toujours la même forme, y compris les 404 :

{ "code": "SCOPE_MANQUANT", "message": "Cette clé n'a pas le scope « articles:read »." }

Le code est stable : testez-le. Le message est destiné à l’humain qui lit le journal, et peut changer d’une version à l’autre.

HTTP code Cause Que faire
400 PARAMETRE_INVALIDE date mal formée, numéro non entier corriger l’appel
401 CLE_MANQUANTE en-tête absent ajouter X-Omag-Cle
401 CLE_INVALIDE clé inconnue, révoquée ou mal formée en demander une nouvelle
403 IP_REFUSEE adresse hors de la liste de la clé faire ajouter votre IP
403 SCOPE_MANQUANT portée non accordée faire cocher la portée
403 MODULE_NON_SOUSCRIT l’option API n’est pas active sur le compte la demander à OMAG
404 INTROUVABLE l’enregistrement n’existe pas ou n’est pas validé
404 TYPE_INCONNU type de document inconnu voir la liste des types
404 ROUTE_INCONNUE chemin inexistant vérifier l’URL
429 QUOTA_DEPASSE plafond par minute atteint respecter Retry-After
500 ERREUR_INTERNE anomalie serveur signaler, avec l’heure et le chemin
503 INDISPONIBLE base injoignable réessayer
503 SOURCE_INDISPONIBLE procédure absente (flux BI) une maintenance la recréera

L’administrateur du compte voit vos erreurs dans Configuration → Clés API → Activité : méthode, chemin, code, heure, adresse IP. C’est la première chose à regarder avant d’ouvrir un ticket.

Chargez une fois, rafraîchissez ensuite. Un intégrateur qui retélécharge tout le catalogue toutes les cinq minutes sature son quota et n’apporte rien de plus que modifie_depuis.

Une clé par usage. Power BI, le site de vente en ligne et le prestataire de passage méritent trois clés différentes : on révoque l’une sans casser les autres, et le journal dit qui fait quoi.

Restreignez les IP quand l’appelant a une adresse fixe : c’est le réglage le plus rentable de l’écran.

Ne partagez jamais une clé par e-mail ou dans un dépôt Git. Elle n’est affichable qu’une fois pour cette raison ; si elle a fuité, elle se révoque — c’est instantané et sans effet sur les autres.

On ajoute des champs, on n’en retire jamais, et on ne change pas le sens d’un champ existant. Un programme écrit contre la v1 continue de fonctionner.

Côté client, cela veut dire : ignorez les champs que vous ne connaissez pas plutôt que de rejeter la réponse. Une rupture nécessaire ouvrirait une /v2, annoncée, avec les deux versions servies en parallèle.

Toutes les évolutions sont datées dans le journal des versions. La sonde publique porte le repère du contrat en cours, donc une supervision peut détecter un changement sans lire cette page :

Fenêtre de terminal
curl https://api.omag.ma:7979/api/v1
# { "api": "omag", "version": "v1", "statut": "ok",
# "contrat": "2026-09-13.2", "journal": "https://docs.omag.ma/developpeurs/changelog/" }