Arpelin

Développeurs

API Arpelin

Récupérez en lecture seule, au format JSON, les commandes en cours, les statistiques de ventes, le catalogue d'articles et le stock d'un établissement. Pratique pour alimenter un écran cuisine, un tableau de bord, un outil comptable ou une application tierce.

Principes

  • Requêtes GET, réponses JSON (toujours un tableau), encodage UTF-8.
  • Chaque établissement a son propre domaine ; l'API ne renvoie que les données de cet établissement.
  • Aucune clé requise pour lister les commandes en cours. Seule l'adresse de livraison est réservée au personnel connecté (voir Authentification).
  • Les statistiques, les articles et le stock demandent une clé secrète (voir Clés API).

URL de base

https://votre-domaine.arpelin.fr/panel/

Remplacez votre-domaine.arpelin.fr par le domaine de l'établissement.

Authentification

Les points d'accès sont publics : aucun en-tête ni jeton n'est nécessaire.

Adresse de livraison. Le champ adresse (mode détaillé) n'est renvoyé en clair que si la requête porte un cookie de session du backoffice appartenant à un compte de rôle admin, manager ou cashier. Sinon il est masqué : seuls le code postal et la ville sont conservés (exemple : ••• 75011 Paris), ou ••• si aucun code postal n'est détecté. Depuis un navigateur déjà connecté, envoyez la requête avec credentials: 'include'.

Formats & erreurs

  • Dates : chaînes AAAA-MM-JJ HH:MM:SS (fuseau du serveur).
  • Montants : nombres décimaux en euros, séparateur point.
  • etat est renvoyé sous forme de chaîne JSON : comparez avec == ou convertissez en nombre.

En cas d'échec, le code HTTP passe à 500 et le corps devient un objet :

{ "error": "Erreur lors de l'exécution de la requête : ..." }

Point d'accès — Commandes en cours

GET /panel/api_gestion

Le paramètre update sélectionne le mode de réponse :

ParamètreValeurEffet
update absent Mode synthétique : une entrée par commande, pour affichage TV.
update présent (ex. update=1) Mode détaillé : contenu du panier, total, adresse.

Mode synthétique — GET /panel/api_gestion

Commandes dont l'horodatage debut est compris entre 12 h avant et 3 h après l'instant courant, avec un état actif (0.5 à 2). Livraisons terminées exclues. Une entrée par commande.

ChampTypeDescription
prepentierNuméro de préparation affiché au client.
etatnombreÉtat de la commande (voir Codes d'état).
debutdatetimeDate et heure de création de la commande.
retraitchaîneMode de retrait (sur place, a emporter, livraison…).
notechaîne | nullNote libre. Peut contenir un marqueur [Nom: …].
file_attenteobjet | nullPosition dans la file et estimation d'attente. Présent uniquement si le module Temps de préparation est actif ; null sinon ou si la commande n'a pas de numéro de préparation. Voir File d'attente.
[
  { "prep": 42, "etat": "1",   "debut": "2026-09-09 12:04:11", "retrait": "sur place", "note": null,
    "file_attente": { "position": 0, "message": "C'est bientôt votre tour", "duree_preparation_min": 6, "duree_estimee_min": 6 } },
  { "prep": 43, "etat": "0.6", "debut": "2026-09-09 12:06:52", "retrait": "livraison", "note": "[Nom: Dupont] sans oignon",
    "file_attente": { "position": 0, "message": "Commande prête", "duree_preparation_min": 12, "duree_estimee_min": 0 } }
]

Sans le module Temps de préparation, la réponse est identique mais sans la clé file_attente.

Mode détaillé — GET /panel/api_gestion?update=1

Commandes du jour et de la veille (DATE(debut) ≥ hier) avec un état actif, livraisons terminées exclues. Une entrée par commande, avec le détail des articles.

ChampTypeDescription
panier_identierIdentifiant de la commande.
prepentierNuméro de préparation.
etatnombreÉtat de la commande (voir Codes d'état).
heuredatetimeDate et heure de création.
retraitchaîneMode de retrait.
totalnombreMontant total dû en euros (toutes lignes incluses, ventilation TVA comprise).
notechaîne | nullNote libre de la commande.
adressechaîneAdresse de livraison. Masquée hors session staff (voir Authentification). Chaîne vide si retrait sur place ou à emporter.
commandestableauArticles de la commande (un objet par article, voir ci-dessous).
file_attenteobjet | nullPosition dans la file et estimation d'attente. Présent uniquement si le module Temps de préparation est actif ; null sinon ou si la commande n'a pas de numéro de préparation. Voir File d'attente.

Objet commandes[]

ChampTypeDescription
nom_articlechaîneLibellé de l'article.
infos_articlechaîne | nullPersonnalisations et options.
quantiteentierQuantité commandée.
prix_articlenombrePrix unitaire complet en euros (ventilation TVA recomposée).
[
  {
    "panier_id": 10432,
    "heure": "2026-09-09 12:06:52",
    "retrait": "livraison",
    "total": 24.5,
    "commandes": [
      { "nom_article": "Burger maison", "infos_article": "sans oignon", "quantite": 2, "prix_article": 9.5 },
      { "nom_article": "Frites",        "infos_article": null,          "quantite": 1, "prix_article": 3.5 },
      { "nom_article": "Coca 33cl",     "infos_article": null,          "quantite": 1, "prix_article": 2.0 }
    ],
    "note": "[Nom: Dupont] 3e étage",
    "adresse": "••• 75011 Paris",
    "etat": "1",
    "prep": 43,
    "file_attente": {
      "position": 2,
      "message": "2 commandes avant vous",
      "duree_preparation_min": 25,
      "duree_estimee_min": 43
    }
  }
]

Objet file_attente

Ajouté à chaque commande des deux modes quand le module Temps de préparation est actif sur l'établissement (menu Modules → File d'attente du backoffice). Sans ce module, la clé est absente. Elle vaut null pour une commande sans numéro de préparation exploitable.

ChampTypeDescription
positionentierNombre de commandes du même jour qui précèdent celle-ci dans la file et ne sont pas encore prêtes. 0 = c'est la prochaine (ou la commande est déjà prête).
messagechaîneFormulation prête à afficher : C'est bientôt votre tour, 1 commande avant vous, N commandes avant vous, ou Commande prête (état 0.6 / 2).
duree_preparation_minentier | nullDurée de préparation propre à cette commande, en minutes (somme des durées configurées par article × quantité). null si aucun de ses articles n'a de durée configurée.
duree_estimee_minentier | nullEstimation du temps d'attente restant avant que cette commande soit prête, en minutes : somme des duree_preparation_min des commandes qui la précèdent et ne sont pas prêtes, plus la sienne. 0 si la commande est déjà prête. null si une des durées nécessaires n'est pas configurée.
Fenêtre de calcul. La position et l'estimation ne portent que sur les commandes renvoyées par la requête (fenêtre −12 h / +3 h en mode synthétique, jour + veille en mode détaillé) et sur le même jour que la commande concernée, le numéro de préparation étant remis à 1 chaque jour. Les durées viennent de la configuration par article du module ; elles ne tiennent pas compte du nombre de postes de préparation.

Codes d'état (etat)

ValeurSignification
0.5À encaisser
0.6Prête à encaisser
1En cours de préparation
2Prête (à remettre au client)

Clés API (v1) : authentification

Les points d'accès /api/v1/stats, /api/v1/articles et /api/v1/stock sont privés : chaque appel doit porter une clé secrète, en lecture seule.

Créer une clé

  1. Connectez-vous au backoffice avec un compte administrateur.
  2. Ouvrez Paramètres avancés (/panel/config?config=advanced), section API : clés secrètes.
  3. Donnez un nom à la clé, cochez les accès voulus (stats, articles, stock) puis cliquez sur Créer une clé.
Conservez la clé immédiatement. Elle n'est affichée qu'une seule fois, à la création. Si elle est perdue ou compromise, révoquez-la depuis la même page (l'accès est coupé aussitôt) et créez-en une nouvelle.

Envoyer la clé

Dans l'en-tête de chaque requête, jamais dans l'URL :

Authorization: Bearer arp_votre_cle_secrete
# ou
X-API-Key: arp_votre_cle_secrete

Chaque clé ne donne accès qu'aux données de son établissement et aux seuls accès cochés à sa création. Toutes les requêtes sont en GET. Ne placez jamais une clé dans une page web publique ou une application distribuée : appelez l'API depuis un programme dont vous maîtrisez l'hébergement.

https://votre-domaine.arpelin.fr/api/v1/

Statistiques : GET /api/v1/stats

GET /api/v1/stats

Accès requis : stats. Renvoie les mêmes chiffres que la page Statistiques du backoffice : chiffre d'affaires, transactions, paiements, ventes par heure et par jour de la semaine, classement des articles, rentabilité et personnel. Les paniers annulés sont exclus.

Paramètres

ParamètreDéfautDescription
start_dateil y a 30 joursDébut de période, AAAA-MM-JJ.
end_dateaujourd'huiFin de période incluse, AAAA-MM-JJ. Durée maximale : 731 jours.
start_time00:00Heure de début le premier jour, HH:MM.
end_time23:59Heure de fin le dernier jour, HH:MM.
granularityautomatiqueday, week ou month : pas de la courbe d'évolution du chiffre d'affaires. Par défaut : jour jusqu'à 30 jours, semaine jusqu'à 90 jours, mois au-delà.
top20Nombre d'articles dans top_articles (1 à 1000).
includetoutListe de sections séparées par des virgules, pour alléger la réponse : summary, sales, payments, hourly, weekly, top_articles, articles, profitability, staff.
pointages0Avec 1, la masse salariale (staff) suit les horaires pointés au lieu du planning prévu.

Réponse

CléContenu
periodPériode calculée (start, end) et pas retenu (granularity).
summaryChiffre d'affaires TTC (revenue), nombre de commandes (transactions), articles vendus (items_sold), panier moyen, prix moyen par article, meilleure période et évolution en % par rapport à la période précédente de même durée (change_vs_previous_period_pct).
sales_over_timeChiffre d'affaires par période : period (2026-09-09, 2026-09 ou 2026-37 pour une semaine) et revenue.
paymentsMontant par moyen de paiement (method, amount).
sales_by_hourChiffre d'affaires pour chacune des 24 heures (hour de 0 à 23).
sales_by_weekdayChiffre d'affaires par jour de la semaine (monday à sunday).
top_articlesArticles les plus vendus : name, quantity, revenue.
articlesClassement complet des articles vendus, avec average_price.
profitabilityMarge par article d'après les coûts de revient renseignés : total et articles[] (revenue_ht, cost, margin, margin_pct, cost_complete, group). Les valeurs sont null quand le coût n'est pas renseigné.
staffHeures et coût du personnel sur la période, part du chiffre d'affaires, chiffre d'affaires et commandes par heure, détail par personne (employees[]).
curl "https://votre-domaine.arpelin.fr/api/v1/stats?start_date=2026-09-01&end_date=2026-09-30&include=summary,payments" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

{
  "period": { "start": "2026-09-01 00:00:00", "end": "2026-09-30 23:59:59", "granularity": "day" },
  "summary": {
    "revenue": 18420.5, "transactions": 912, "items_sold": 2210,
    "average_basket": 20.2, "average_item_price": 8.33,
    "best_period": { "period": "2026-09-27", "revenue": 1104.0 },
    "change_vs_previous_period_pct": { "revenue": 6.4, "transactions": 3.1, "basket": 3.2, "items": 4.9 }
  },
  "payments": [
    { "method": "Carte bancaire", "amount": 12980.3 },
    { "method": "Espèces", "amount": 5440.2 }
  ]
}

Articles : GET /api/v1/articles

GET /api/v1/articles

Accès requis : articles. Les articles de la carte, comme dans la page Articles du backoffice, triés dans l'ordre d'affichage, avec pagination.

ParamètreDéfautDescription
idUn seul article.
category_idArticles d'une catégorie.
enabled1 pour les articles actifs, 0 pour les désactivés.
qRecherche dans le nom.
limit100Nombre d'articles par page (1 à 500).
offset0Décalage pour la page suivante.
includecategories et/ou customizations pour joindre la liste complète des catégories et des personnalisations.

Objet articles[]

ChampTypeDescription
id, name, descriptionIdentifiant, nom et description.
category_id, categoryCatégorie de l'article.
pricenombrePrix TTC en euros.
vat_rate, vat_codeTaux et code de TVA.
costnombre | nullCoût de revient, si renseigné.
enabledbooléenArticle actif ou non.
orderentierPosition d'affichage.
allergens, barcodeAllergènes et code-barres.
hide_pricebooléenPrix masqué en boutique.
loyalty_points_costentier | nullCoût en points de fidélité.
stock, stock_trackedUnités restantes (null si le suivi de stock est désactivé pour l'article).
imagestableauURL des images.
customization_idstableauIdentifiants des personnalisations proposées, dans l'ordre. Détail avec include=customizations.

La réponse contient aussi total (nombre d'articles correspondant au filtre), limit et offset. Une catégorie (categories[]) porte id, name, description, enabled, order, subcategory_ids et images. Une personnalisation (customizations[]) porte id, category, type, name, price, enabled, max_quantity, extra_price_threshold, extra_price, cost et images.

curl "https://votre-domaine.arpelin.fr/api/v1/articles?category_id=3&enabled=1&limit=2" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

{
  "total": 14, "limit": 2, "offset": 0,
  "articles": [
    { "id": 21, "name": "Burger maison", "description": "Boeuf, cheddar, salade",
      "category_id": 3, "category": "Burgers", "price": 9.5, "vat_rate": 10.0, "vat_code": null, "cost": 3.2,
      "enabled": true, "order": 1, "allergens": "gluten, lait", "barcode": null, "hide_price": false,
      "loyalty_points_cost": null, "stock": null, "stock_tracked": false,
      "images": ["https://votre-domaine.arpelin.fr/images/articles/burger.webp"],
      "customization_ids": [42, 43] }
  ]
}

Stock : GET /api/v1/stock

GET /api/v1/stock

Accès requis : stock. Le stock des composants (ingrédients, emballages) tel qu'affiché dans l'onglet Stock du backoffice. Le stock d'un composant est théorique : dernier inventaire, plus les entrées, moins les pertes, la casse, les démarques et la consommation des ventes d'après les compositions.

ParamètreDéfautDescription
includecomponents,articlesSections à renvoyer, séparées par des virgules : components, alerts, movements, compositions, articles.
statusFiltre les composants : ok, rupture (sous le seuil minimum) ou surstock.
component_idLimite les composants et les mouvements à un composant.
movements_from, movements_to30 derniers joursPériode des mouvements, AAAA-MM-JJ.
movement_typeentree, perte, casse, demarque ou inventaire.
movements_limit200Nombre maximum de mouvements (1 à 1000), les plus récents d'abord.
SectionContenu
components[]id, name, unit, theoretical_stock, status, unit_cost, stock_value, min_threshold, max_threshold, last_inventory_at, last_inventory_gap et since_last_inventory (entries, losses, consumed_by_sales).
alerts[]Points d'attention : level (red ou orange), type (rupture, surstock, ecart), component, message.
movements[]id, component_id, component, unit, type, quantity (pour un inventaire : quantité comptée), gap, unit_cost, note, date.
compositions[]Quantité de composant consommée par unité vendue : target (article ou customization), target_id, component_id, quantity_per_unit_sold.
articles[]Stock par article : id, name, enabled, stock_tracked, stock (null si non suivi), out_of_stock.
curl "https://votre-domaine.arpelin.fr/api/v1/stock?include=components&status=rupture" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

{
  "generated_at": "2026-09-09 14:30:02",
  "components": [
    { "id": 7, "name": "Steak haché", "unit": "kg", "theoretical_stock": 1.8, "status": "rupture",
      "unit_cost": 11.5, "stock_value": 20.7, "min_threshold": 3.0, "max_threshold": 12.0,
      "last_inventory_at": "2026-09-08 22:10:00", "last_inventory_gap": -0.4,
      "since_last_inventory": { "entries": 5.0, "losses": 0.3, "consumed_by_sales": 6.1 } }
  ]
}

Erreurs de l'API v1

Le corps d'une erreur est un objet { "error": "...", "message": "..." }.

Code HTTPerrorCause
400bad_requestParamètre invalide (date mal formée, valeur hors limites, section inconnue).
401unauthorizedClé absente, inconnue ou révoquée.
403forbiddenLa clé n'a pas l'accès demandé (stats, articles ou stock).
405method_not_allowedMéthode autre que GET.

Exemples

curl

# Mode synthétique
curl https://votre-domaine.arpelin.fr/panel/api_gestion

# Mode détaillé
curl "https://votre-domaine.arpelin.fr/panel/api_gestion?update=1"

# Mode détaillé avec adresse complète (session backoffice)
curl "https://votre-domaine.arpelin.fr/panel/api_gestion?update=1" \
  --cookie "PHPSESSID=VOTRE_ID_DE_SESSION"

JavaScript (navigateur)

async function chargerCommandes() {
  const res = await fetch('https://votre-domaine.arpelin.fr/panel/api_gestion', {
    credentials: 'include' // envoie le cookie de session si connecté au backoffice
  });
  if (!res.ok) throw new Error('HTTP ' + res.status);
  const commandes = await res.json();

  for (const c of commandes) {
    const prete = c.etat == 0.6 || c.etat == 2;
    console.log(`Prép ${c.prep} — ${prete ? 'PRÊTE' : 'en cours'}`);
  }
}

setInterval(chargerCommandes, 5000);
chargerCommandes();

Statistiques, articles et stock avec une clé (curl)

curl "https://votre-domaine.arpelin.fr/api/v1/stats?start_date=2026-09-01&end_date=2026-09-30" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

curl "https://votre-domaine.arpelin.fr/api/v1/articles?include=categories,customizations" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

curl "https://votre-domaine.arpelin.fr/api/v1/stock?include=components,alerts,movements" \
  -H "Authorization: Bearer arp_votre_cle_secrete"

Python

import requests

BASE = "https://votre-domaine.arpelin.fr/api/v1"
HEADERS = {"Authorization": "Bearer arp_votre_cle_secrete"}

stats = requests.get(f"{BASE}/stats", headers=HEADERS,
                     params={"start_date": "2026-09-01", "end_date": "2026-09-30",
                             "include": "summary,top_articles"}, timeout=30)
stats.raise_for_status()
print(stats.json()["summary"]["revenue"])

Extraire le nom du client depuis note

function nomClient(note) {
  if (!note) return null;
  const m = note.match(/\[(?:Nom|Name)[^:]*:\s*([^\]]+)\]/i);
  return m ? m[1].trim() : null;
}